Errors

The error envelope, HTTP status codes, and error codes returned by the Management API.

Envelope

Every error uses one envelope — the same shape as the Inference API's, with one addition, action:

{
  "error": {
    "message": "this token does not carry the projects:write scope",
    "type": "permission_error",
    "code": "insufficient_scope",
    "param": "projects:write",
    "action": "Mint a token that includes projects:write in Settings → API Tokens.",
    "request_id": "req_2fb3a75644e94b719e13b23639e5ff22"
  }
}
FieldNotes
typeThe error class; always matches the HTTP status (table below).
codeStable machine-readable code. Branch on code, never on message.
messageA human sentence. It may be reworded at any time.
paramThe offending parameter, body field, header or scope, or null. Nested body fields use a dotted path (guardrails.spend_limit_usd).
actionA short human fix, present where the fix is not obvious from the code. May be absent.
request_idAlways present; equals the X-Request-Id response header. Quote it to support. Request ids look like req_ followed by 32 hex characters (req_6f1c2d9e8a4b4c3d9e2f1a2b3c4d5e6f); treat them as opaque strings. An X-Request-Id you send is ignored; the response always carries a new one.

Status and type

StatustypeWhenRetry?
400invalid_request_errorMalformed or unknown body field, bad parameter value, bad limit/cursor, missing Idempotency-Key. param names the field.No — fix the request.
401authentication_errorMissing, invalid, expired or revoked token; wrong credential type. Generic where the reason would leak.No — fix the credential.
403permission_errorinsufficient_scope: the token lacks the scope, or its owner's current role or project access does not allow the call. The message names which.No.
404not_found_errorThe object does not exist or belongs to another organization — indistinguishable on purpose. Also any path that is not a Management API endpoint.No.
409conflict_errorThe current state doesn't allow it: last admin, the organization owner, acting on yourself, the default project, a taken name or slug, a revoked key, no rotation to cancel, an Idempotency-Key reused for a different request.No — change state first.
422validation_errorUnderstood but refused by rule: an unknown query parameter, a filter value out of range, an export that matches too many rows.No.
429rate_limit_errorPer-token rate limit reached.Yes, after Retry-After seconds.
500api_errorOur fault (internal_error).Yes, with exponential backoff and the same Idempotency-Key.
502api_errorA service the API depends on is temporarily unavailable (upstream_unavailable).Yes, with exponential backoff and the same Idempotency-Key.

400 means "say it properly"; 422 means "that is understood and not allowed".

Error codes

These are all the codes the Management API returns.

CodeStatusMeaning
missing_credential401No Authorization: Bearer header.
credential_type_mismatch401A project API key, a portal session or another bearer that is not a personal access token was sent. The message names the right credential.
invalid_credential401Unknown token, or its owner or organization no longer exists. Deliberately generic.
token_expired401The token is past expires_at. Mint a new one.
token_revoked401The token was revoked, its owner was disabled, or the organization is suspended.
rate_limit_exceeded429Per-token rate limit reached. See Rate limits.
insufficient_scope403Token scope missing (param names it), or the owner's role or project access does not allow the call (the message says which).
invalid_request400A body field, query value, limit, cursor or header is malformed or unknown. param names it.
idempotency_key_required400A POST, PATCH, PUT or DELETE without Idempotency-Key.
idempotency_conflict409The Idempotency-Key was already used in the last 24 hours for a different request, or the first request with it is still in progress.
idempotency_replay_unavailable409A key create or rotate already succeeded under this Idempotency-Key, but its one-time secret is not available for replay. The secret was delivered once, on the original response; retry with a new Idempotency-Key and revoke the unused key. See Idempotency.
not_found404The object does not exist or is in another organization, or the path is not a Management API endpoint.
conflict409Any other state conflict; the message explains it.
last_admin409The change would leave the organization without an active admin.
owner_protected409The organization owner's role cannot be changed, and the owner cannot be removed.
cannot_act_on_self409You cannot disable or remove yourself.
sessions_unavailable409The member has no active sign-in session to end.
default_project_protected409The default project cannot be renamed, disabled or deleted.
name_taken409You already have an active key with this name (names are unique among each creator's active keys; param: "name").
slug_taken409The organization slug could not be saved because it is already in use (param: "slug").
key_revoked409The key was permanently revoked (deleted) and cannot be enabled again.
no_rotation_in_progress409There is no rotation on this key to cancel.
unsupported_filter422A query parameter the endpoint does not support (param names it). Filters are never silently ignored.
validation_failed422A filter value outside what the endpoint accepts, for example status=archived, or a group_by=day range over 31 days.
export_too_large422An export matches more than 10,000 rows. Narrow from/to and export in windows.
internal_error500Something failed on our side, including verifying your token. Retry; if it persists, contact support with the request_id.
upstream_unavailable502A service the API depends on was unreachable. For a write, the request may or may not have been applied — retry with the same Idempotency-Key.

Note

Minting a token happens in the portal, not on this API, so the mint errors (for example token_limit_reached when you already hold 20 active tokens) are shown in the portal's token dialog and are not Management API codes. See Mint policy.

Stability promise

Once a code appears in a released version, its meaning never changes and it is never reused for something else. New codes may be added within v1 — handle unknown codes by falling back on the HTTP status and type. Removing a code is a breaking change and gets a new version. See Versioning.

Handling errors in code

curl -sS -w '\n%{http_code}\n' https://portal.<domain>/api/v1/mgmt/projects/0d5c2b8e-4f1a-4c7e-9b3d-2a6f8e1c9d40 \
  -H "Authorization: Bearer $TF_PAT"