Skip to content

Ask AI

Ask anything about Destesi — setup, products, APIs.

Powered by Claude. Answers may be wrong — always verify against the docs.

Troubleshooting

Most preview problems fall into a few buckets. Start with dst preview trace — it shows status, recent events, and a log tail in one view — then match the symptom below.

Terminal window
dst preview trace prev_abc

This is the fastest first move: it prints the current status, the event timeline (newest first), and a tail of the container logs. If you only need one part:

Terminal window
dst preview show prev_abc # status + last_error
dst preview events prev_abc # the event timeline
dst preview logs prev_abc -f # follow the logs live

pending → building → starting → healthy, with terminal states failed (build/run/config error) and deleted (torn down).

  • Stuck in pending for more than a minute → the controller isn’t picking it up.
  • Stuck in building / starting for more than ~10 minutes → the build is slow (cold image cache) or a container is hung.
  • healthy means reachable over HTTP, not just scheduled — so if it’s healthy but you can’t load it, the problem is almost always inside your app.
Symptom What to check
dst preview wait exits 2 (timeout) The timeout is too short for a cold docker compose up --build. A fresh repo’s first build often takes 5–8 minutes. Re-run with --timeout 15m. If it still times out, dst preview trace and look for a stalled container.
dst preview wait exits 1 with compose parse failed The uploaded source didn’t contain a compose file at the repo root. Confirm your --from-dir layout, or that the repo root has docker-compose.yml / docker-compose.destesi.yml. See the compose precedence.
Status failed with an env-resolution error An env template doesn’t resolve. Check the available references. A genuinely unknown namespace or field is rejected; ${s3.*} and ${preview.*} are accepted syntactically but currently resolve to an error because no such endpoint is attached to the fork.
403 FORBIDDEN on any dst preview call The API key lacks scope or targets the wrong workspace. dst api-key list and confirm you’re using the right key; check DESTESI_WORKSPACE. A preview-runner key is scoped to preview:write on one workspace.
Preview stuck in pending The controller isn’t polling. Confirm the controller is running and that CONTROLLER_SECRET matches between the API and the controller — a 404 on /v1/controller/previews means the secret is unset on the API side; a 401 means it mismatches.
New preview goes to failed with a NodePort error The NodePort pool (range 30452–30471, 20 slots) is exhausted. dst preview list --status healthy and delete previews you no longer need.
Preview healthy but the app returns 500s The overlay is up but your app is erroring. dst preview logs prev_abc --container service:<name> to read that service’s logs, or open the in-preview pod logs (Cmd+Shift+L) and network tap (Cmd+Shift+N).
OAuth login redirects to a 400 / wrong URL NEXTAUTH_URL is set in the env — remove it. With trustHost: true, Auth.js uses the preview’s forwarded host. See OAuth passthrough.
OAuth callback lands on state mismatch Passthrough is disabled because the overlay’s OAuth state secret isn’t configured, so the provider returns the raw (now-unrecognized) state. Check the overlay logs for a passthrough-disabled warning.
Preview agent git_commit / git_push errors The preview was created from a local directory (--from-dir), which extracts without a .git directory. Commit/push only work for GitHub-source previews.

Create is refused before anything is provisioned

Section titled “Create is refused before anything is provisioned”

Preview checks the workspace’s plan allowance before it claims a NodePort or forks a branch, so these refusals arrive immediately and nothing is left half-created:

Response Meaning Fix
429 quota_exceeded The workspace is at its plan’s active environment allowance. The body carries used, limit, and remaining. Delete previews you no longer need, then create again.
403 The workspace is suspended or lacks the entitlement to run previews. Check the workspace’s plan and standing in account settings.
503 Preview could not read your plan’s allowance and refused rather than guessing. Retry shortly. This one fails closed on purpose — admitting on an unreadable policy would let a workspace provision past whatever it is entitled to.

Only previews in the workspace you are creating in count. Every preview route — create, list, get, and events — also requires you to be a member of that workspace; a non-member gets 403 regardless of allowance.

GitHub-source previews can’t fetch the repo

Section titled “GitHub-source previews can’t fetch the repo”

If a GitHub-source preview fails to fetch its source:

  • The GitHub connection isn’t active. GitHub source is resolved through your workspace’s connection in Connect. If it isn’t connected (or has been revoked), reconnect at connect.destesi.io.
  • The repository isn’t covered by the app installation. Make sure the Destesi GitHub App is installed on that repository (or the GitHub organization that owns it) in Connect.
  • A connection that exists but isn’t ACTIVE fails the fetch loudly rather than silently falling back — reconnect to clear it.

A preview needs a source database to fork from. If creation complains it has no source, or the app boots without data:

  • Confirm a Snap remote exists for the workspace: dst snap remote list.
  • Pass --from-remote <name|id> (or --from-snap <id>) explicitly — there is no inherited default. A preview with neither flag is not rejected: it builds and runs with no database at all, and its event timeline records skipped snap fork (no source configured). So “the app boots but has no data” is the symptom of a missing flag, not of a broken fork. The CLI and the web dashboard each pick a healthy remote for you before the create call; a workflow that hardcodes the create gets whatever it passes and nothing more.
  • If the create is rejected outright with connector is not accessible in workspace, the remote exists but is not shared with this workspace — register it here, or pass a remote that is.
  • Confirm your compose file references ${DATABASE_URL} (or your declared variable) rather than a hardcoded localhost DSN — see writing a preview-specific compose file.

The forked branch is copy-on-write and write-isolated: data you create during review never reaches the source or another preview, and it’s discarded when the preview is deleted. See Snap for the branching model.

When a preview misbehaves, walk this in order:

  1. dst preview show <id> — what status does the API report, and is there a last_error?
  2. Still pending after a minute → the controller isn’t polling.
  3. Reached building but never healthydst preview logs <id> (or trace) and look for a compose build failure or a container that exits non-zero.
  4. healthy but the app errors → check the specific service’s logs (--container service:<name>); the overlay being up doesn’t mean your app is.
  5. Env looks wrong → dst preview show <id> lists the declared env; confirm the resolved value reached the right service (declared env is fanned into every service via a generated override).