Troubleshooting
Remember one thing first: give the error’s code and hint to your AI
agent. Keelson errors are designed so that agents can read them and make the
necessary correction. If you investigate the problem yourself, check the
following in order.
Identify where the process stopped
Section titled “Identify where the process stopped”keelson status # App and latest deployment statuskeelson diagnose <deploy_id> # Diagnose a failed deploymentkeelson logs deploy <deploy_id> # Progress logs and details of a failed deploymentkeelson logs app <slug> # App standard output and standard errorWhen a deployment fails, keelson logs deploy also shows the saved details. If
the app exits during startup, its stored startup logs preserve the traceback or
process error for that deployment. Read them with
keelson logs deploy <deploy_id> or keelson diagnose <deploy_id> before
checking the listening port and health.path. The same commands can be used
later to investigate dependency or Dockerfile build failures, unset secrets,
and configuration or migration errors. Build output from successful deployments
is not saved. If there are no progress logs or saved failure details to show,
the command only explains why no logs are available.
In the console, the app page has a failure summary under Overview, deployment logs under View logs on Deploys, and app logs under Logs.
| Where it stopped | What to inspect | Common causes |
|---|---|---|
| Before upload (CLI preflight check) | Command output | Missing go.mod for a Go app; a Node app with only a pnpm or yarn lockfile; pip install in command; missing db.mode; unquoted env values |
| Validation | code and message | Retired workers or databases fields; reserved names; plan limits |
| Build | Deployment logs | Dependency resolution failure; mismatch between package.json and package-lock.json; private registry; build script error |
| Startup | Stored startup logs in keelson logs deploy <deploy_id> | Not listening on 0.0.0.0; hard-coded PORT; exception caused by an unset secret |
| Health check | Stored startup logs, then app logs | The app exited during startup; / returns 5xx; startup takes more than 120 seconds |
| Migration | Deployment logs | SQL error in db.migrate. The previous revision continues running |
| Running but not behaving as expected | App logs and access logs | See Runtime problems below |
Common failures
Section titled “Common failures”I pressed Ctrl-C during a deploy
Section titled “I pressed Ctrl-C during a deploy”Ctrl-C stops only this client from watching. The deploy is still running server-side
and may still become the active version. Use the deploy_id shown
by the CLI to check its progress:
keelson status <deploy_id>If you do not want the new version, wait for the deploy to finish and then return to the previous completed deploy:
keelson rollback --app <slug>If the app has no earlier completed deploy, stop it after the deploy finishes:
keelson app stop --app <slug>It works locally but fails on Keelson
Section titled “It works locally but fails on Keelson”- Listening on
localhost— change it to0.0.0.0 - Hard-coding the port — read the
PORTenvironment variable - Depending on files that only exist locally — such as
.env, a local database file, or files covered by.gitignore. Checkarchive.excludedin the output ofkeelson deploy --check --jsonto see what was excluded - Environment variables are not set — values that exist only in your local
.envare not available on Keelson. Declare them insecretsand set their values - Using file-based SQLite — neither
/datanor/tmpis persistent. Move the data to Managed SQLite
A Node app’s lockfile is rejected
Section titled “A Node app’s lockfile is rejected”Keelson’s Node builder uses npm, so dependency pinning requires npm’s
package-lock.json. Run npm install in the project root, commit the generated
package-lock.json, and deploy again.
You do not need to delete pnpm-lock.yaml or yarn.lock. The app can be
deployed with either file alongside package-lock.json, and the build uses
package-lock.json.
Data disappears
Section titled “Data disappears”Check whether you are writing to a local file. Files in /tmp, /data, and the
app directory are lost on restart, redeployment, or an idle stop. Store the data
in a database or with the
Files / Media SDK.
Background processing does not run
Section titled “Background processing does not run”Work after a response is returned, in-app timers, and threads do not run. Finish
the work synchronously within the request or move it to crons. See
Scheduled Jobs.
A cron does not run
Section titled “A cron does not run”- Check whether the schedule is shorter than the plan’s minimum interval (it is rejected during deployment)
- Check whether the previous run is still in progress (overlapping runs are skipped)
- Check whether the monthly execution limit has been reached (remaining runs for the month are skipped)
- Check whether the app is suspended
- Check the run history on the Scheduled Jobs tab for the reason it was skipped
The UI does not change after an update
Section titled “The UI does not change after an update”The cause is the browser cache. Confirm that the deployment has finished, then
perform a hard reload (Mac: Cmd + Shift + R; Windows: Ctrl + Shift + R). A
static-site redeployment takes 25–30 seconds to propagate to the edge.
A user says “I can’t access the app”
Section titled “A user says “I can’t access the app””- Are they a workspace member, and have they accepted their invitation?
- Are they blocked?
- Are they in a group with permission to view the app?
- Are they signed in with the registered account?
- Are they denied by IP access controls? The 403 page shows the source IP.
See Members and roles for details.
”No App Slot is available” (503)
Section titled “”No App Slot is available” (503)”This means the concurrent App Slot limit has been reached. Apps accessed in the last 5 minutes use a slot. Wait about 5 minutes, enable priority start for an important app, or upgrade your plan.
504 Gateway Timeout
Section titled “504 Gateway Timeout”The app did not start its response within 120 seconds. Shorten the operation,
send headers first by streaming, or move heavy work to crons. Server-side work
may finish even after a 504 response, so make write operations idempotent.
A webhook returns 401 or 403
Section titled “A webhook returns 401 or 403”- Check whether the path is declared in
auth.endpoints(it must start with/api/webhooks/or/api/external/) - Check whether the method matches the declaration
- Check whether the token scope and allowed IP addresses match
Secret changes are not reflected
Section titled “Secret changes are not reflected”Secrets are injected at deployment time. Redeploy the app or select Apply in the console.
If the problem persists
Section titled “If the problem persists”If you receive a platform error such as deploy.platform.error, or if the steps
above do not solve the problem, include the deploy_id (available from
keelson status --json) when you contact us.