Skip to content

Error codes

Preview Every API error carries a stable machine code, a broad type that maps to an HTTP status, a param pointing at the offending field where relevant, and a doc_url that links straight to the matching anchor on this page. Match on code in your client — it’s the part that won’t change.

error response
{
"error": {
"type": "not_found",
"message": "site not found",
"code": "site.not_found",
"param": "site_id",
"doc_url": "https://docs.managed.dev/reference/error-codes/#site.not_found"
},
"request_id": "req_01J9F2KQ"
}

The doc_url anchor is built from the codesite.not_found links to #site.not_found on this page — so an error always points the reader at its own explanation. Always log the request_id; it’s what support uses to find your request.

The type is the coarse category and fixes the HTTP status. There are eight:

type HTTP Meaning
invalid_request 400 The request is malformed — a bad field, a missing parameter, a reused idempotency key.
authentication 401 The key is missing, malformed, expired, or revoked.
permission 403 You’re authenticated and can see the resource, but your scope doesn’t allow the action.
not_found 404 The resource doesn’t exist — or you can’t see it (existence hiding).
conflict 409 The request conflicts with current state, or the runtime can’t perform it.
rate_limit 429 You exceeded a rate-limit bucket. Honor Retry-After.
quota_exceeded 402 / 429 A plan quota is exhausted (sites, storage, envs).
api_error 500 Something went wrong on our side. Safe to retry idempotent requests.

code is the precise, stable identifier — there are many, namespaced by resource; these are the ones you’ll handle most.

code type HTTP When you see it
site.not_found not_found 404 No site with that id, or your key can’t see it.
environment.not_found not_found 404 No such environment under the site.
environment.capability_unsupported conflict 409 The route exists but this runtime can’t perform the action — e.g. installing a plugin on a static site.
auth.invalid_key authentication 401 Key missing, malformed, expired, revoked, or blocked by its IP allowlist.
scope.insufficient permission 403 You can see the resource but your key lacks the scope for this action.
rate_limit.exceeded rate_limit 429 A per-key or per-team bucket is empty. Wait Retry-After seconds.
idempotency.key_reused invalid_request 400 An Idempotency-Key was reused with a different request body.
quota.exceeded quota_exceeded 402 A plan limit (sites, storage, environments) is reached.
validation.failed invalid_request 400 A field failed validation; param names which one.
conflict.state conflict 409 The resource is in a state that forbids the action — e.g. deleting an environment mid-deploy.

The most important distinction in the error model is when you get a 404 instead of a 403 — it’s deliberate, and it preserves existence hiding:

  • 404 for things you can’t see. If your key is constrained to one site and you request another, you get site.not_found — not “forbidden”. The API never confirms the existence of a resource outside your resource constraint. A capability that’s structurally absent on a runtime is also a 404.
  • 403 for things you can see but can’t act on. If you can see a resource (it’s within your constraint) but your key lacks the scope for the action, you get scope.insufficient — a 403. This isn’t a leak, because you could already enumerate the resource.

Ordering guarantees you only ever receive a 403 for something you were already entitled to know exists. See errors for the full model.