PandaStack

Troubleshooting

Symptoms you will actually hit on PandaStack, what causes them, and how to fix them — HTTP status codes, failed deploys, sandboxes that will not start, and database connection problems.

Every entry below is a real failure, with the symptom you see first. If you know the HTTP status or the error text, search this page for it.

Nothing here is hypothetical — each item is a failure mode that occurs in practice, with the specific fix.

Quick triage by HTTP status

StatusUsually meansGo to
401Missing or wrong API keyAuthentication
402Free credit exhausted; workspace paused402 Payment Required
404Wrong ID, or resource belongs to another workspaceWrong workspace
411POST sent with no body through the edge411 Length Required
502No agent could take the request — usually capacity502 Bad Gateway
503App is paused (out of credit)App serves 503

Billing and quota

402 Payment Required: "free quota exceeded"

Symptom. Creating a sandbox, app, or database returns:

{ "error": "free quota exceeded",
  "detail": "This account has used its free credit. Add a payment method to keep creating sandboxes." }

Cause. Your workspace used its full monthly free credit ($5.40). At 100%, compute stops: running resources are paused and new creates are refused. This is a deliberate cost guard — it stops runaway spend rather than billing you for it.

Fix. Add a payment method or upgrade. The pause lifts on the next reconcile (within about a minute) and your resources resume where they left off. If you would rather wait, the free credit resets at the start of each month and the pause lifts automatically.

Your data is safe. Nothing is deleted when you run out of credit — not on a timer, not after a grace period. Code, data, volumes, and settings are kept for as long as the workspace exists. See Billing.

Your app URL returns 503 "This app is paused"

Symptom. Visitors get a plain page saying the app is paused, with Retry-After set. The X-Pandastack-App: suspended response header confirms it.

Cause. The workspace is out of free credit, so the app's compute is stopped. A paused app is deliberately not woken by traffic — otherwise it would burn credit on every visit.

Fix. Same as above: add a payment method, or wait for the monthly reset. The app resumes automatically; you do not need to redeploy.

The 503 is intentional rather than a 404: it tells crawlers the app is temporarily unavailable and coming back, so your URL is not de-indexed.


Capacity

502 Bad Gateway on create

Symptom. POST /v1/sandboxes returns 502 — often after several creates that succeeded seconds earlier.

Cause. No agent had room. Each sandbox reserves its template's baked memory (the base template is 4 GiB), so a host's RAM is the real ceiling, not any sandbox count limit. On a small fleet you can hit this after only a handful of concurrent sandboxes.

Fix.

  1. Delete sandboxes you are no longer using — DELETE /v1/sandboxes/{id}. Capacity frees immediately.
  2. Give sandboxes a ttl_seconds so abandoned ones reap themselves.
  3. Use a smaller template where you can: code-interpreter and agent bake at 2 GiB versus base at 4 GiB, so they fit roughly twice as densely.
  4. Retry with backoff — 502 here is transient, not a permanent rejection.

Concurrency is bounded by fleet memory. If you need a specific concurrency figure for a workload, measure it against your own fleet rather than assuming a number — and get in touch before relying on high concurrency in production.


Deploying apps

Build fails in npm install with node-gyp / "No module named 'distutils'"

Symptom. The deploy log ends with a native build failure:

npm error command sh -c prebuild-install || (node-gyp rebuild ...)
npm error prebuild-install warn install No prebuilt binaries found (target=24.x ...)
npm error ModuleNotFoundError: No module named 'distutils'
npm error gyp ERR! not ok

Cause. One of your dependencies ships a native addon with no prebuilt binary for the Node version the build resolved, so npm fell back to compiling it with node-gyp — and the build image's Python is 3.12+, which removed distutils.

Fix. Pin the runtime your dependency actually publishes binaries for. Most packages target the current LTS:

mise.toml
[tools]
node = "22"
python = "3.11"

Node 22 is the version most native addons ship prebuilt binaries for, so nothing compiles. The python pin is a safety net for the case where something still does build from source.

.nvmrc is not read. Runtime versions come from mise.toml or .tool-versions. A repo pinning Node only in .nvmrc silently gets the default, which is the most common cause of this failure.

Deploy succeeds, then the health check fails

Symptom. The build finishes but the deploy ends at waiting for app to listen on :<port>.

Cause. Almost always one of two things:

  1. The app binds 127.0.0.1. The health check and the proxy both reach your app over the VM's network interface, so a loopback-only listener is unreachable — exactly as it would be behind any container platform or load balancer.
  2. The app ignores $PORT. PandaStack injects PORT; if your server hardcodes a different one, nothing is listening where we look.

Fix. Bind all interfaces and honour $PORT:

app.listen(process.env.PORT || 3000, "0.0.0.0");
uvicorn.run(app, host="0.0.0.0", port=int(os.environ["PORT"]))

Build runs out of memory

Symptom. The build dies abruptly, often with JavaScript heap out of memory or a bare Killed.

Cause. Apps run at a fixed 4 GiB / 8 vCPU. Firecracker cannot resize a VM at snapshot restore, so an app's size comes from its template's baked size — setting memory_mb on the app does not change what it actually gets.

Fix. Reduce peak build memory: cap the Node heap (NODE_OPTIONS=--max-old-space-size=3072), disable source maps for production builds, or build fewer targets at once. If a build genuinely needs more than 4 GiB, it cannot run on the stock base template — bake a custom template with more memory (--memory-mb) and set it on the app.

Files my app wrote have disappeared

Symptom. Uploads, generated files, or a SQLite database vanish after a redeploy — or after the app has been idle.

Cause. An app's local disk is ephemeral. A redeploy provisions a fresh sandbox, and scale-to-zero replaces the running VM as well. Only what is in your repository plus what the build produces survives.

Fix. Keep durable state outside the app:

This is the same constraint as any ephemeral-filesystem platform; design for it rather than around it.


Databases

Connection refused, or connection_url missing from the API response

Symptom. GET /v1/databases/{id} returns the database with status: "hibernated" and no connection_url.

Cause. Idle databases auto-suspend to stop billing. A suspended database has no live endpoint until it is woken.

Fix. Either connect anyway — the proxy wakes the database on connect — or wake it explicitly and poll until status is running:

curl -X POST https://api.pandastack.ai/v1/databases/$ID/wake \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" -d '{}'

To keep a database from ever suspending, set always_on:

curl -X PATCH https://api.pandastack.ai/v1/databases/$ID \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" -d '{"always_on": true}'

411 Length Required on a POST

Symptom. A POST with no body — wake, failover, reset-credentials — returns 411, with no JSON body.

Cause. The edge rejects a bodyless POST before it reaches the API.

Fix. Always send a body, even an empty object, and set the content type:

curl -X POST .../wake -H "Content-Type: application/json" -d '{}'

TLS errors connecting to a managed database

Symptom. Your client refuses the connection, or reports a certificate problem.

Cause. Managed databases require TLS. Clients that default to plaintext fail to connect at all.

Fix. Enable TLS normally — the certificate chains to a public CA, so no custom root certificate and no verification bypass is needed:

  • psql → append ?sslmode=require to the URL.
  • Node (pg) → ssl: true.
  • Directus and similar → DB_SSL=true.

If a tool asks you to disable certificate verification to connect, that is a misconfiguration on the client side, not a requirement of the service.


Authentication

401 Unauthorized

Cause. Missing, malformed, or revoked API key.

Fix. Send the key as a bearer token, and confirm the variable is actually set in the shell you are running in:

curl https://api.pandastack.ai/v1/sandboxes \
  -H "Authorization: Bearer $PANDASTACK_API_KEY"

The environment variable the SDKs and CLI read is PANDASTACK_API_KEY. An older PANDASTACK_TOKEN name was removed — if you are following an outdated snippet, that is why nothing is authenticating.

404 on a resource you know exists

Cause. Resources are scoped to a workspace. A valid ID belonging to a different workspace reads as "not found" — deliberately, so IDs cannot be probed across tenants.

Fix. Confirm you are using the key for the right workspace, and that your current organization is the one that owns the resource (GET /v1/me).


Still stuck?

  • Build and runtime logs are the fastest signal: GET /v1/apps/{id}/deploys/{deployID}/logs for the build, and GET /v1/apps/{id}/runtime-logs for your app's own stdout/stderr.
  • For a sandbox, GET /v1/sandboxes/{id}/logs returns the Firecracker console — useful when a VM never becomes reachable.
  • Email hello@pandastack.ai with the resource ID and the timestamp; those two things make an incident traceable end to end.

On this page