Skip to content

Error codes

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 built as https://docs.managed.dev/errors/<type>/<code> — so an error always points at its own explanation. 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/errors/not_found/site.not_found"
},
"request_id": "req_01J9F2KQ"
}

The doc_url is derived from the type and codescope.insufficient links to /errors/permission/scope.insufficient. 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, an unsupported value.
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 — an idempotency clash, or a runtime that can’t perform the action.
quota_exceeded 429 A plan quota is exhausted (sites, storage, envs).
rate_limit 429 You exceeded a rate-limit bucket. Honor Retry-After.
api_error 500 Something went wrong on our side. Safe to retry idempotent requests.

code is the precise, stable identifier. Each code below is an anchor, so you can link a code straight to its explanation.

Your key can see the resource but lacks the scope this action requires. The message names the missing scope. Mint or down-scope a key that carries it.

No site with that id — or your key’s resource constraint can’t see it (existence hiding; see the 404-vs-403 split).

No build artifact with that id — check GET /v1/sites/{id}/artifacts before rolling a deployment.

No function with that id, or it doesn’t belong to a site you can see.

No API key with that id under your account.

No job with that id.

No webhook endpoint with that id.

No delivery with that id under the given webhook endpoint.

The generic fallback when the missing resource has no dedicated code.

An Idempotency-Key was reused with a different request body inside the 24-hour window. Reusing a key with the same body replays the original response instead.

The original request with this Idempotency-Key is still in flight. Wait for it to finish, then retry — the replay will return its response.

The endpoint is real and you’re allowed to call it, but this site’s runtime can’t perform the action — for example, executing WP-CLI on a static site. Ask GET /v1/sites/{id}/capabilities first to avoid it.

A function declares a binding kind the platform doesn’t support — for example, cron bindings are rejected for customer functions.

A function’s language isn’t one the build toolchain supports.

A per-key or team bucket is empty. Wait the Retry-After seconds before retrying — don’t retry tighter.

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.
  • 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.