Real failures the platform has thrown — not hypotheticals. Each entry:
match (exact substring to look for in a response body or logs) → cause
→ fix.
Covers the whole platform surface: deploying (POST /apps) and everything
you can do to a project afterward (env vars, memory, rollback, custom
domains, monitoring). See docs.md for the full API reference
this troubleshooting guide assumes, and
limitations-and-recommendations.md
for the platform's real constraints and how to design around them —
before you hit them, not after.
"window.storage" in the 422 response detailwindow.storage, a Claude Artifacts sandbox API that doesn't exist outside itbetter-sqlite3, simple key/value) or @electric-sql/pglite
(relational) — write under DATA_DIR either way, see
Only DATA_DIR survives a redeploy
— then redeploy{"error":"Unauthorized","code":"unauthorized"}Authorization header present but token invalid/revoked. Omitting the header entirely = anonymous
deploy (fine). Sending a broken one is never silently treated as anonymous."already in use by a different company"X-App-Name is also the live subdomain — must be unique across the whole platform, not just your accountX-App-Name, or claim the existing orphan with a real token before its 24h expiry"code":"app_name_check_failed""OOM Killed", Exit Code: 137PATCH .../memory {"memoryMb": 1024}, then redeploy or roll back — this endpoint only persists the
new value, it does not itself push it to the running app (see
Changing memory doesn't take effect immediately below)"Not Restarting", "Exceeded allowed attempts"GET .../logs, find the actual cause above this line, fix it, redeploy (resets the attempt counter)"pull access denied"CompileError from WebAssembly.compile/instantiate, or a CSP violation
naming script-src; page itself loads (200) but renders blankpackage.json,
so they're served by Railpack's own built-in static-file server) inherited that server's default
Content-Security-Policy, which didn't include 'wasm-unsafe-eval' in script-src. This platform sets no
CSP of its own at the edge before this fix, so whatever the app's own container happened to set is what a
browser saw.'wasm-unsafe-eval') at the edge for every app,
which takes precedence over anything the app's own container sets. Confirm with
curl -sI https://<app>.app.embarko.ai/ | grep -i content-security-policy; if it's still missing
wasm-unsafe-eval, the app hasn't been redeployed since this fix — trigger any redeploy (even a no-op
rollback to the current version) to pick it up.{"error":"Not found"} from GET .../status or .../logsAuthorization: Bearer <deploy token> for a claimed app; omit the header entirely if it's
still meant to be an orphanRenamed 2026-09-09: this was .../feature-requests on all three paths (dashboard, public, agent);
now .../customer-query. Same data, same behavior, type now also accepts "other" alongside
"feature"/"feedback".
"X-Agent-Name header is required"POST <ship host>/apps/:appName/customer-query (the agent-facing path)
without the X-Agent-Name headerX-Agent-Name: <your agent's name> — free text, any value identifying the calling agent worksPOST .../apps/:appName/customer-querytype must be exactly
"feature", "feedback", or "other"; message 1–5000 characters)"DNS does not yet point at the platform"POST .../domains response exactly, then retry
.../verify after propagation — safe to retry repeatedly"Not resolving yet" even though the CNAME/A record in your DNS
provider matches what was given exactly.../verify — should pass within a minute
or two, since no real propagation delay is involved, just the proxy-mode changematch — this is a design constraint, not an errorCNAME to a dedicated, permanently-unproxied
platform hostname; an apex domain (yourdomain.com with no subdomain) can't use CNAME at
all under standard DNS rules, so it gets an A record pointing directly at the platform's
origin server IP instead. That means an apex custom domain talks to the origin directly —
whatever CDN/DDoS protection you'd normally get from proxying (Cloudflare, etc.) doesn't
apply to it.app.yourdomain.com) over an apex domain if you want to keep your
own CDN/proxy in front of traffic to this appmatch — a design constraint that surfaces as verification silently never succeeding/.well-known/acme-challenge/*
specifically. If your own infrastructure in front of this domain (a firewall, a different
proxy) blocks or redirects port 80 before it reaches the platform, verification/cert
issuance will never complete.match — this is by design, not a bugAuthorization header at all creates an unclaimed ("orphan")
project that's automatically torn down (the running app, its routing, and its image all
removed) 24 hours after creation, unless claimed firstX-App-Name with a valid token before it expires — this claims
the project under your company, cancels the expiry, and behaves exactly like any other
project from then on. There is only one warning: the deploy response's orphan.message
and an in-app banner (see below) — no reminder email as it approaches expiry.match — a known scope limitation, not a bugtext/html HTTP responses only (a sidecar
proxy in front of your app, working regardless of your app's language/framework). A
JSON-only API with no HTML page has nothing for it to inject into — the deploy response's
orphan.message is still the authoritative notice, it just never reaches a browser{"accepted":true}, HTTP 202, from POST /appsstatusUrl from the response until deploy.status is "success" or "failed"; never treat
202 itself as done{"accepted":true,"deploymentId":"...","statusUrl":"..."}, HTTP 202, from
POST .../deployments/:deploymentId/rollbackstatusUrl (GET .../deployments/:deploymentId) until its status is no
longer "in_progress"524, "A timeout occurred""code":"rollback_image_unavailable", message starts with "Cannot roll back: the image is no longer available"limitations-and-recommendations.md —
the response's own retainCount field always says exactly how many). The target version's image has
already been pruned.retainCount deployments instead (see GET .../deployments), or
redeploy the old source fresh if you still have it — either way, the exact number is in the error
response itself, not something you need to look up separatelyPOST .../deployments/:deploymentId/rollback, error does NOT start with
"Cannot roll back: the image is no longer available"status !== "success") or has no recorded image tagGET .../deployments — only successful ones with an image are
valid rollback targetsmatch — a behavior to know about, not an errorPATCH .../memory only persists the new value in the dashboard's database. It does not push
a config change to the already-running app.POST /apps), a rollback, or a custom-domain change all do this. If you just need the new memory limit
applied with no code change, roll back to the current version — that re-applies the current
configuration with the new memory floor and no rebuildmatch — a behavior to know about, not an errorPUT .../env-vars, trigger a new deploy (POST /apps, even with unchanged source) for the app
to actually see the new values — see docs.md's
Environment variables section for the exact stepsThese aren't things that go wrong — they're the actual shape of the platform, worth designing around
rather than assuming stronger guarantees than it makes. Moved to their own doc, paired with concrete
recommendations for building around each one: see
limitations-and-recommendations.md.