Patterna Docs

Error codes

Stable codes from the API, the SDKs and the panel login, and what to do.

Developers 7 min read View as Markdown

Every API error has a stable code. Branch on the code, not on the message. Every error also carries the request_id; quote it when you ask for help. The error body is described in the API overview.

The tables below list every code the engine returns on the integration paths (serve, ingest, users, flows, experiments, keys), with its status. "Fall back" means: show your own list and keep the page working; "fix" means a bug or a configuration mistake that a fallback must not hide.

API: serve and ingest#

CodeStatusMeaningWhat to do
bad_request400a missing or invalid field, an unknown JSON field (bodies are decoded strictly), an empty body or a body over 2 MiB; the message names the problemfix the request
unauthorized401missing, revoked or expired keyfix the key
wrong_scope401a serve or ingest key on another scope's path (pk_s_ serve, pk_i_ ingest, pk_a_ admin passes everywhere)use the key of the right scope
not_found404a path the API does not have, answered in the usual error bodycheck the path and the /v1 prefix
unknown_surface404no surface with that keyfix the surface key
unknown_request404POST /interactions (or /abandon) with a request_id that has no impressionreport with the request_id from the slate; for your own list report nothing
unknown_item422an interaction for an item_id that is not in the slate; details.unknown_item_ids lists themreport only items from the slate
displayed_position_required422an interaction on a device_resort surface without displayed_positionsend where the app showed the item
bad_tester_id422X-Patterna-Tester with a value other than 1send 1 or leave the header out
webhook_not_configured401a Shopify webhook for a tenant without shopify_webhook_secretset the secret with PATCH /settings
bad_signature401a Shopify webhook whose X-Shopify-Hmac-Sha256 does not matchcheck the secret in Shopify and in Patterna
item_not_found404a catalog call for an external_id and kind that do not existcheck the id and the kind query parameter
surface_off409the surface's status is offfall back; expected while a surface is off
not_shown409POST /recommendations/{request_id}/abandon for a slate answered with shown: falsenothing to do: hide the block; the slate already counts in its arm
mode_conflict422a user_id on a non_profiled request; PUT /users/{user_id}/profile with mode non_profiled, or without mode for a user who opted outfix: send only session_id in non_profiled mode; set the mode explicitly before a profile. A consent bug is a privacy bug
mode_required422PUT /users/{user_id}/profile without mode for a user Patterna does not know yetsend mode (personalized or cohort) with the profile, or set it first with PUT /users/{user_id}/mode
no_candidates422no published item of the surface's kinds and locale survives the flow's filtersfall back, then check the catalog sync, the locale and the filters
pii_rejected422a catalog item attribute named email, name or ipremove the attribute
rate_limited429the key's token bucket is empty (serve 200/s, burst 400; ingest 50/s, burst 100); Retry-After: 1fall back on serve; retry ingest later. Never retry recommend
quota_exceeded429the plan's monthly serve requests are used; details carries quota, used and resets_at (the 1st of next month, UTC). Interactions, events and the catalog keep workingshow your own list until the reset; never retry recommend. Ask us to raise the quota; a quota_warning notification arrived at 90%
internal500an unexpected error; logged with the request_idfall back; quote the request_id
unavailable503storage did not answer in time or could not be reached (a timed-out key lookup answers this, never 401); Retry-After: 1fall back on serve, retry once elsewhere; alert if it persists

Events are not rejected as a batch for content. POST /events answers 202 and lists problem events in rejected[] with a reason (unknown type, invalid signature, user_id or session_id malformed, …), and counts removed props in dropped_fields. See Ingest. Each entry in rejected[] also carries a stable code: invalid_event, pii_rejected (with fields, the paths, never the values), invalid_signature, no_signing_secret (a signed event while the tenant has no secret), unknown_request, unknown_item or displayed_position_required. The batch still answers 202.

API: admin#

CodeStatusMeaningWhat to do
bad_request400also an invalid flow config: config.generators must hold at least one generator, unknown generator kind …, ranker.kind must be linear, learned_linear or gbdt, ranker.kind lambdamart is not available yet, filters.diversity must be between 0 and 1, exploration.kind must be none or plackett_luce, exploration.share must be between 0 and 0.5; an experiment with a primary_metric other than tap_rate, second_item_rate, join_rate, engaged_after_tap or purchase_ratefix the config; see Flow config reference
forbidden_role403a panel session (or key) whose role may not do this: viewers read only, editors configure, owners manage keys, people and secretsask an owner
forbidden_scope403an admin key tried to mint an admin keyan owner mints admin keys in the panel
session_required403an action tied to a person (approvals, saved views) called with a keyuse the panel
not_found404the object does not exist for this tenantcheck the id
unknown_flow_version404preview of a flow version that does not existcheck the version
experiment_running409the surface already has a running experimentend it with POST /experiments/{id}/end first
approval_required409activating a flow on a live surface while the two-person rule is onrequest an approval
approval_pending409an approval for the same change is already openwait for it or reject it
exists409a surface, key or member with that name already existspick another name
deletion_scheduled409a workspace deletion is already scheduledcancel it first
unknown_items422a curated list or gold set names items that are not in the catalogfix the ids
invalid_reason_template400a flow's reasons names an unknown reason key or generator kind, locale or placeholderuse the keys and placeholders in Reason keys
signing_secret_exists409POST /settings/signing-secret when a secret already existsrotate instead
metric_not_applicable400an experiment with primary_metric: join_rate on a surface without communities, or purchase_rate on a surface without productspick a metric that fits the surface

TypeScript SDK#

Every failure is a PatternaError with code, op, status, requestId, details and a transient getter.

Code or classMeaningWhat to do
consent_required (ConsentError)recommend without a mode, or an unknown modealways pass the user's mode; a consent bug is a privacy bug
consent_violation (ConsentError)a non_profiled request with a user_id or without a session_idfix the caller; nothing was sent
ValidationErrorbad input, for example an email or auth0|... as user id, or a context key outside the allowlistfix the caller; the id is never in the message
TimeoutErrorthe per-call budget ran outshow your own list
NetworkErrorno answershow your own list; idempotent calls were retried once
ApiErrorthe API answered with an error; code is the API'ssee the API table

withFallback falls back on every SDK error except ConsentError and ValidationError, which it rethrows. That includes an ApiError with status 400, 401, 404 or mode_conflict: log code and alert on those, so a bug does not hide behind your own list. The SDK has typed errors for no_candidates, surface_off and unknown_surface.

Go SDK#

Every error is *Error{Code, Op, Status, RequestID, Message, Details}. Compare with errors.Is or patterna.IsAPIError(err, "pii_rejected").

SentinelMeaningWhat to do
ErrTimeoutthe deadline passed (budget or a shorter caller deadline)serve your own list
ErrAbortedthe caller cancelled the contextnothing
ErrCircuitOpenthe breaker for this scope is open after 5 failures; it stays open 30 sserve your own list; watch OnBreakerChange
ErrQueueFullthe interaction report queue (1024) is full; the report was droppedcheck DroppedReports(); look for a slow API
ErrUnknownSurfacethe API answered 404 unknown_surface; RecommendWithFallback serves your own list and sets rec.Causea configuration bug: alert on it
ErrUnknownItemmatches the API code unknown_item (422, an interaction for an item not in the slate) whatever the statusreport only items from the slate
ErrItemNotFoundmatches the API code item_not_found (404 from the catalog calls GetItem, DeleteItem, SetItemStatus, SetItemTags; SDK 0.4.1)check the id and the kind

Consent and opaque-id checks in Go fail before anything is sent, like in the TypeScript SDK.

Panel login#

These come from the panel's auth endpoints, which are not in the contract yet.

CodeMeaningWhat to do
invalid_credentialswrong email or passwordtry again
rate_limitedtoo many attemptswait a moment
mfa_pendingsigned in, MFA not done yet (401 from /auth/me)enter the MFA code
mfa_invalidwrong MFA codetry again with a fresh code
sso_<reason>the Orven one-click login failed; the suffix says whysign in with email and password
esc
  • Type to search every page, heading and code sample.