What errors can the API return?
http://localhost:3001 Every error from the Daemion gateway follows the same JSON shape and uses standard HTTP status codes. This page catalogs every status code and every error message the gateway can return, verified against src/gateway/server.ts.
What does an error response look like?
All errors return a JSON body with at least an error field:
{ “error”: “message text here” }
Some errors include additional fields alongside error:
{ “error”: “agent not found”, “agent_id”: “my-agent” }
{ “error”: “validation failed”, “details”: { … } }
The Content-Type is always application/json. The HTTP status code is always set correctly — never 200 with an error body.
What status codes does the gateway use?
| Code | Name | When it appears |
|---|---|---|
400 | Bad Request | Missing fields, invalid JSON, failed validation, bad parameters |
401 | Unauthorized | Missing or invalid bearer token, failed OTP verification |
403 | Forbidden | Path traversal attempt, path outside home directory, cannot modify essential extensions |
404 | Not Found | Thread, extension, app, project, agent, file, entity, or proposal does not exist |
405 | Method Not Allowed | HTTP verb not supported for this route |
413 | Content Too Large | Request body exceeds size limit, soul content exceeds 100KB |
429 | Too Many Requests | OTP rate limit exceeded |
500 | Internal Server Error | Unexpected server-side failure |
501 | Not Implemented | Feature unavailable in the current gateway configuration |
502 | Bad Gateway | Dev server proxy failed |
400 — Bad Request
The most common error code. Covers every case where the request itself is malformed or missing required data.
Invalid or missing JSON
{ “error”: “Invalid JSON” } { “error”: “invalid JSON” }
The request body could not be parsed. Check that you are sending valid JSON and that Content-Type: application/json is set.
Missing required fields
{ “error”: “Request body required” } { “error”: “otp field required” } { “error”: “q is required” } { “error”: “agent_id is required” } { “error”: “name and path are required” }
Validation failures
{ “error”: “validation failed”, “details”: { … } } { “error”: “invalid domain config”, “details”: { … } } { “error”: “name must be kebab-case (a-z, 0-9, hyphens)” } { “error”: “content must be a string” }
The details field contains the structured Zod or validation error — inspect it to find which fields failed and why.
Agent errors
{ “error”: “agent not found”, “agent_id”: ”…” } { “error”: “agent is disabled”, “agent_id”: ”…” }
The agent_id echo helps identify which agent ID caused the failure.
Thread and turn errors
{ “error”: “invalid role: …” }
The role field on a turn must be one of the valid values. The invalid value is echoed back in the message.
Mode errors
{ “error”: “unknown mode: …” }
An unrecognized mode value was provided. The invalid value is echoed in the message.
Extension errors
{ “error”: “extension has no disk path” } { “error”: “disk-config not supported for type ’…’” } { “error”: “path query param required” } { “error”: “path traversal not allowed” }
path traversal not allowed means the resolved path escaped the extension’s root directory.
App errors
{ “error”: ”… apps do not use a dev server” }
The requested dev server operation is not valid for this app’s subtype.
Filesystem errors
{ “error”: “query too short (min 2 chars)” } { “error”: “path must be within home directory: …” }
Domain and proposal errors
{ “error”: “domain parameter required” } { “error”: “invalid path segment” } { “error”: “failed to reject proposal” }
401 — Unauthorized
{ “error”: “unauthorized” } { “error”: “Invalid or expired code” }
unauthorized is returned when the Authorization: Bearer header is missing or the token does not match the gateway’s stored token. The bearer token is set during device pairing — it is not user authentication.
Invalid or expired code is returned when an OTP submitted to /pair is wrong or has expired.
403 — Forbidden
{ “error”: “path outside home directory” } { “error”: “permission denied” } { “error”: “cannot disable essential extensions” } { “error”: “cannot delete essential extensions” }
Filesystem endpoints (/filesystem/ls, /filesystem/search) reject paths outside the user’s home directory. This is a security boundary — all paths are resolved and validated before any filesystem operation.
Essential extensions are built-in extensions that Daemion requires to operate. They can be inspected but not disabled or deleted.
404 — Not Found
{ “error”: “not found” } { “error”: “app not found”, “name”: ”…” } { “error”: “thread not found” } { “error”: “extension not found” } { “error”: “project not found” } { “error”: “agent not found” } { “error”: “file not found” } { “error”: “entity not found” } { “error”: “path not found” } { “error”: “proposal not found” } { “error”: “No running dev server for …” }
not found (generic) is the catch-all for unmatched routes. The more specific messages identify what resource is missing. The name field on app not found echoes the requested app name for easier debugging.
405 — Method Not Allowed
{ “error”: “method not allowed” }
The route exists but does not support the HTTP method you used (e.g., POST on a GET-only endpoint).
413 — Content Too Large
{ “error”: “request body too large” } { “error”: “soul content too large (max 100KB)” }
request body too large applies to the general request body size limit enforced by the gateway. soul content too large is specific to the soul file write endpoints — soul files are capped at 100KB.
429 — Too Many Requests
{ “error”: “Too many attempts. Wait a minute and try again.” }
The OTP verification endpoint (POST /pair) rate-limits failed attempts. Wait 60 seconds before retrying.
500 — Internal Server Error
{ “error”: “internal server error” } { “error”: “invalid app definition” } { “error”: “could not read directory” } { “error”: “search failed” } { “error”: “update failed” } { “error”: “Failed to start: …” } { “error”: “Failed to restart: …” }
internal server error is the generic fallback. The more specific 500 messages carry context: Failed to start and Failed to restart include the underlying error message from the OS or process. Check the gateway logs for the full stack trace.
501 — Not Implemented
{ “error”: “Pairing not available — gateway started without token” } { “error”: “Pairing not available” }
The pairing endpoints require the gateway to have been started with a token. If the gateway was started without one (e.g., in a trusted local environment), pairing operations return 501.
502 — Bad Gateway
{ “error”: “Dev server proxy failed” }
The gateway attempted to proxy a request to a running Vite dev server for an app, but the dev server did not respond or returned an error. Verify the dev server process is running and healthy.
Frequently asked questions
error string field and the appropriate HTTP status code. Some errors include additional fields (details, agent_id, name) but error is always present. You can safely write a single error handler that reads response.error.POST /pair (OTP verification). On a 429 response, wait 60 seconds before retrying — the error message says so explicitly. No Retry-After header is set, but the wait window is always 60 seconds.~/.daemion/.gateway-token on the host machine. The token is set during device pairing and is case-sensitive. Re-pair the device if you've lost the token. The header format must be Authorization: Bearer <token> — no other schemes are accepted.details field contains the raw Zod error object. Each failing field appears as a key with an array of issue objects, e.g. { "type": [{ "message": "Invalid enum value" }] }. Inspect the field names to find exactly what failed.What can go wrong
401 {"error": "unauthorized"} — The $DAEMION_TOKEN variable is not set or doesn’t match ~/.daemion/.gateway-token. Export it before running curl: export DAEMION_TOKEN=$(cat ~/.daemion/.gateway-token).
400 {"error": "invalid JSON"} — Missing Content-Type: application/json header, or the JSON body has a syntax error. Validate your JSON with echo '...' | python3 -m json.tool before sending.
403 {"error": "path outside home directory"} — The filesystem endpoints only serve paths within the user’s home directory. Absolute paths starting outside ~ are rejected regardless of permissions.
413 {"error": "request body too large"} — The gateway enforces a request body size limit. If you’re writing large content, check that you’re not sending unnecessary whitespace or encoding overhead.
501 {"error": "Pairing not available"} — The gateway was started without a token. Start it with daemion start (which generates or reads the token) rather than running the server file directly.
What’s next?
- Conversations API — send turns to agents and read thread history
- Extensions API — manage the 12 extension types
- WebSocket events — subscribe to real-time events from the gateway