Skip to content

Troubleshooting

SymptomCheck
401 Authentication requiredBearer header exists and session is not expired/logged out
403 Insufficient permissionMembership contains a role allowed for the operation
403 Attendee is outside the allowed groupsUser and instance group memberships overlap
409 Instance is not bookableInstance is scheduled and audience is not nobody
409 Instance is fullCapacity and confirmed bookings
409 Entitlement has expiredEntitlement expiry and server clock
402 Payment failedPayment gateway result and merchant configuration
Readiness failsDatabase connectivity, credentials, migrations, and application logs
/docs assets return 404VitePress base is /docs/ and npm run build:docs ran

Failed public-environment replacements

Production and demo deploy in parallel from the same immutable image, but each has its own backup, migration, candidate, readiness check, deployment record, and route switch. If one candidate fails during image pull, migration, startup, readiness, release verification, or route switching, the other environment continues independently. The failed job prints a phase-specific ::error annotation and a bounded diagnostic block with that container's state, restart count, health state, candidate release, and still-active release. Recent application logs are redacted before they are printed, and only the failed candidate is removed while its active route and the other environment remain untouched by the failed job.

On the VPS, inspect the same state with:

sh
sudo cat /opt/booking-saas/releases/production-active
sudo cat /opt/booking-saas/releases/demo-active
sudo docker ps -a --filter 'name=booking-production-' --filter 'name=booking-demo-'
sudo docker inspect --format 'status={{.State.Status}} exit={{.State.ExitCode}} restart={{.RestartCount}} health={{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' CONTAINER
sudo docker logs --tail 80 CONTAINER 2>&1 | sed -E \
  -e 's#(mysql://[^:/[:space:]]+):[^@[:space:]]+@#\1:[REDACTED]@#gi' \
  -e 's#(Bearer[[:space:]]+)[^[:space:]]+#\1[REDACTED]#gi' \
  -e 's#((password|passwd|token|secret|authorization|cookie|set-cookie)[=:][[:space:]]*)[^[:space:]]+#\1[REDACTED]#gi' \
  -e 's#[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}#[REDACTED_EMAIL]#gi' \
  -e 's#https?://[^/@[:space:]]+:[^/@[:space:]]+@#https://[REDACTED]@#gi'

Replace CONTAINER with the name printed by docker ps. Each active marker is the release that remains routed after a failed replacement for that environment. If a failure is caused by configuration, correct the relevant file under /opt/booking-saas/secrets/, verify its mode is 0600, and rerun the Deploy workflow; do not delete or restart the active containers as recovery.

API errors are JSON. Reverse-proxy, browser, or HTML errors usually indicate routing rather than domain validation.

When reporting a problem, include the request path, status, timestamp, environment, and correlation information available from the gateway—but never include magic-link tokens, sessions, database credentials, or payment secrets.

Booking SaaS implementation documentation