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"
}
}| Field | Notes |
|---|---|
type | The error class; always matches the HTTP status (table below). |
code | Stable machine-readable code. Branch on code, never on message. |
message | A human sentence. It may be reworded at any time. |
param | The offending parameter, body field, header or scope, or null. Nested body fields use a dotted path (guardrails.spend_limit_usd). |
action | A short human fix, present where the fix is not obvious from the code. May be absent. |
request_id | Always 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
| Status | type | When | Retry? |
|---|---|---|---|
| 400 | invalid_request_error | Malformed or unknown body field, bad parameter value, bad limit/cursor, missing Idempotency-Key. param names the field. | No — fix the request. |
| 401 | authentication_error | Missing, invalid, expired or revoked token; wrong credential type. Generic where the reason would leak. | No — fix the credential. |
| 403 | permission_error | insufficient_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. |
| 404 | not_found_error | The object does not exist or belongs to another organization — indistinguishable on purpose. Also any path that is not a Management API endpoint. | No. |
| 409 | conflict_error | The 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. |
| 422 | validation_error | Understood but refused by rule: an unknown query parameter, a filter value out of range, an export that matches too many rows. | No. |
| 429 | rate_limit_error | Per-token rate limit reached. | Yes, after Retry-After seconds. |
| 500 | api_error | Our fault (internal_error). | Yes, with exponential backoff and the same Idempotency-Key. |
| 502 | api_error | A 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.
| Code | Status | Meaning |
|---|---|---|
missing_credential | 401 | No Authorization: Bearer header. |
credential_type_mismatch | 401 | A 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_credential | 401 | Unknown token, or its owner or organization no longer exists. Deliberately generic. |
token_expired | 401 | The token is past expires_at. Mint a new one. |
token_revoked | 401 | The token was revoked, its owner was disabled, or the organization is suspended. |
rate_limit_exceeded | 429 | Per-token rate limit reached. See Rate limits. |
insufficient_scope | 403 | Token scope missing (param names it), or the owner's role or project access does not allow the call (the message says which). |
invalid_request | 400 | A body field, query value, limit, cursor or header is malformed or unknown. param names it. |
idempotency_key_required | 400 | A POST, PATCH, PUT or DELETE without Idempotency-Key. |
idempotency_conflict | 409 | The 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_unavailable | 409 | A 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_found | 404 | The object does not exist or is in another organization, or the path is not a Management API endpoint. |
conflict | 409 | Any other state conflict; the message explains it. |
last_admin | 409 | The change would leave the organization without an active admin. |
owner_protected | 409 | The organization owner's role cannot be changed, and the owner cannot be removed. |
cannot_act_on_self | 409 | You cannot disable or remove yourself. |
sessions_unavailable | 409 | The member has no active sign-in session to end. |
default_project_protected | 409 | The default project cannot be renamed, disabled or deleted. |
name_taken | 409 | You already have an active key with this name (names are unique among each creator's active keys; param: "name"). |
slug_taken | 409 | The organization slug could not be saved because it is already in use (param: "slug"). |
key_revoked | 409 | The key was permanently revoked (deleted) and cannot be enabled again. |
no_rotation_in_progress | 409 | There is no rotation on this key to cancel. |
unsupported_filter | 422 | A query parameter the endpoint does not support (param names it). Filters are never silently ignored. |
validation_failed | 422 | A filter value outside what the endpoint accepts, for example status=archived, or a group_by=day range over 31 days. |
export_too_large | 422 | An export matches more than 10,000 rows. Narrow from/to and export in windows. |
internal_error | 500 | Something failed on our side, including verifying your token. Retry; if it persists, contact support with the request_id. |
upstream_unavailable | 502 | A 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"