Error codes

Every Culprit API error response has the shape:

{
  "error": {
    "type": "authentication_error",
    "code": "token_invalid",
    "message": "...",
    "doc_url": "https://docs.theculprit.ai/api/errors#token_invalid"
  }
}

Switch on error.code, never on the human error.message. The doc_url field links directly to the anchor below.

CodeTypeStatusMeaning
missing_authorizationauthentication_error401

No `Authorization` header was sent.

Fix: Add `Authorization: Bearer culprit_live_...` to the request.

invalid_authorization_schemeauthentication_error401

The `Authorization` header was present but did not use the `Bearer` scheme.

Fix: Use `Authorization: Bearer <token>` — Basic, Digest, and other schemes are not supported.

token_invalidauthentication_error401

The bearer token is malformed, revoked, or its creator was deleted. The same code is returned for all four cases (malformed shape, no matching prefix, hash mismatch, orphaned by user deletion) to avoid leaking which.

Fix: Mint a new token at /settings/api-tokens.

unauthenticatedauthentication_error401

A downstream Postgres RPC reported an unauthenticated session. Should never reach the wire — the auth middleware guarantees a JWT — and is included as a defense-in-depth surface.

Fix: Retry; if it persists contact support@theculprit.ai with the request id.

token_scope_insufficientpermission_error403

A read-only token attempted a mutating request (POST / PATCH / PUT / DELETE).

Fix: Use a read-write token. Read-only tokens cannot mint other tokens (no scope escalation).

forbiddenpermission_error403

The authenticated user lacks the workspace capability required for this operation (e.g. only owners can delete services or manage tenant members).

Fix: Have a workspace owner perform the action, or have your role elevated. See /concepts/auth-and-scopes for the capability matrix.

rate_limit_exceededrate_limit_error429

Per-token rate limit (1000 req/min sliding window) exceeded.

Fix: Honor the `Retry-After` response header. Different tokens have independent budgets.

invite_resend_rate_limitedrate_limit_error429

Resending a tenant invitation more often than the per-invite cooldown allows.

Fix: Wait for the cooldown to expire and retry. Honor the `Retry-After` header.

param_invalid_formatinvalid_request_error400

A path, query, or body parameter did not match the operation's schema. The `param` field on the error body names the offending key.

Fix: See the `param` field in the error response and fix the offending value.

id_malformedinvalid_request_error400

A resource id in the URL path was not in the expected `<resource>_<base32>` shape.

Fix: Always use the `id` value returned by the API — never hand-construct ids. See /concepts/ids-and-times.

limit_invalidinvalid_request_error400

The `limit` query parameter was outside the allowed range for the endpoint.

Fix: Use a `limit` between 1 and 100 (default: 25).

cursor_malformedinvalid_request_error400

The `cursor` query parameter is malformed, expired, or from a different sort key.

Fix: Always use the `next_cursor` value from the previous response — never construct cursors by hand.

no_fields_to_updateinvalid_request_error400

A PATCH request was sent with an empty body, so there is nothing to update.

Fix: Send at least one mutable field in the request body.

pattern_invalidinvalid_request_error400

A submitted PII regex pattern failed the re2js compile gate (linear-time safety check).

Fix: Adjust the pattern to be RE2-compatible (no backreferences, no lookaround). See /concepts/redos-safety.

service_name_in_useinvalid_request_error400

A service with this name already exists in this workspace.

Fix: Pick a different name; service names must be unique per workspace.

api_token_name_in_useinvalid_request_error400

An API token with this name already exists in this workspace.

Fix: Pick a different name; API token names must be unique per workspace.

dispatch_target_name_in_useinvalid_request_error400

A dispatch target with this name already exists in this workspace.

Fix: Pick a different name; dispatch target names must be unique per workspace.

pii_pattern_name_in_useinvalid_request_error400

A PII pattern with this name already exists in this workspace.

Fix: Pick a different name; PII pattern names must be unique per workspace.

duplicate_pendinginvalid_request_error400

A pending invitation for this email address already exists in this workspace.

Fix: Resend or revoke the existing invitation instead of creating a new one.

already_memberinvalid_request_error400

The invited email belongs to a user who is already a member of this workspace.

Fix: Promote / demote the existing member via the tenant_members API instead of inviting them again.

invite_already_acceptedinvalid_request_error400

This invitation was already accepted and cannot be acted on again.

Fix: No action required — the invitee is now a tenant member.

invite_revokedinvalid_request_error400

This invitation was revoked and cannot be resent.

Fix: Create a fresh invitation instead.

cannot_change_selfinvalid_request_error400

You cannot change your own role via the API — guard against self-lockout.

Fix: Have another owner change your role.

cannot_remove_selfinvalid_request_error400

You cannot remove yourself via the API — guard against self-lockout.

Fix: Have another owner remove you, or transfer your work and have them remove your seat.

cannot_promote_to_ownerinvalid_request_error400

Promotion to `owner` must go through the dedicated transfer-ownership flow, not a generic role update.

Fix: Use the ownership-transfer flow in /settings/team rather than PATCHing the member role.

last_ownerinvalid_request_error400

The action would leave the workspace with zero owners (e.g. removing or demoting the last owner).

Fix: Promote another member to owner first, then retry.

idempotency_key_reusedidempotency_error422

An `Idempotency-Key` was reused with a different request body.

Fix: Use a fresh idempotency key when the body changes; reusing a key is only valid for retrying the IDENTICAL request.

route_not_foundnot_found_error404

The path/method combination is not part of the API surface.

Fix: Check /api for the canonical endpoint list.

service_not_foundnot_found_error404

No service with this id exists in your workspace. Returned with status 400 when supplied as a foreign key on another resource (e.g. notification rule), and 404 when fetching `/v1/services/<id>` directly.

Fix: Verify the id, or list /v1/services to find the right one.

incident_not_foundnot_found_error404

No incident with this id exists in your workspace.

Fix: Verify the id, or list /v1/incidents to find the right one.

audit_event_not_foundnot_found_error404

No audit event with this id exists in your workspace.

Fix: Verify the id, or list /v1/audit_events to find the right one.

api_token_not_foundnot_found_error404

No API token with this id exists in your workspace.

Fix: Verify the id, or list /v1/api_tokens to find the right one.

dispatch_target_not_foundnot_found_error404

No dispatch target with this id exists in your workspace.

Fix: Verify the id, or list /v1/dispatch_targets to find the right one.

notification_rule_not_foundnot_found_error404

No notification rule with this id exists in your workspace.

Fix: Verify the id, or list /v1/notification_rules to find the right one.

pii_pattern_not_foundnot_found_error404

No PII pattern with this id exists in your workspace.

Fix: Verify the id, or list /v1/pii_patterns to find the right one.

tenant_member_not_foundnot_found_error404

No tenant member with this id exists in your workspace.

Fix: Verify the id, or list /v1/tenant_members to find the right one.

tenant_invitation_not_foundnot_found_error404

No tenant invitation with this id exists in your workspace.

Fix: Verify the id, or list /v1/tenant_invitations to find the right one.

tenant_not_foundnot_found_error404

The tenant context for this token could not be resolved.

Fix: Mint a fresh token; if the issue persists contact support@theculprit.ai.

internal_errorapi_error500

Something failed on Culprit's side and was logged.

Fix: Retry with backoff. If the error persists, contact support@theculprit.ai with the request id.

email_send_failedapi_error500

A transactional email (e.g. tenant invitation, invite resend) could not be delivered to Resend.

Fix: Retry the operation; persistent failures usually indicate a Resend outage — check status.resend.com and contact support@theculprit.ai if it persists.