Skip to content

Error Codes

This page lists all error and reason codes the SDK may return, organized by category.

Returned in decision.reasonCodes[] to explain why a placement was or wasn’t shown. This is the complete set the SDK emits — generated from the public reason contract (tests/reason-contract.json in revturbine-sdk-internal), the same file reason-contract.test.ts enforces against live SDK fixtures. Do not hand-edit the table below; run pnpm gen:reason-codes (from pages-build/) after the contract changes.

CodeMeaning
config_unavailableThe Playbook could not be fetched, or a fetch is still in flight — the SDK has no config to decide against yet.
entitlement_gate_unmetThe candidate’s entitlement-gate trigger did not match the user’s current entitlement state.
entitlement_not_deniedThe Access Gate placement’s entitlement is not denied or limited for this user, so the gate does not fire.
gate_outside_access_gateAn Access Gate placement was requested from a slot that is not an Access Gate slot; gates render only in gate slots.
no_eligible_candidateNo candidate placement survived eligibility filtering for this slot.
no_gate_for_entitlementThe Access Gate slot asks for an entitlement that no gate placement is authored for, so the slot shows its access-denied placeholder.
no_resolver_configuredNo placement resolver is configured, so the SDK has nothing to evaluate against.
placement_not_foundNo candidate output matched the requested placement id or name.
placement_not_registeredThe payload targets a placement handle the app never registered with the SDK.
placement_retiredThe candidate’s rule is hidden — for example, superseded by a conversion — per impression history.
plan_target_mismatchThe user’s plan or billing period doesn’t match the candidate’s plan targeting.
qualifier_trigger_unmetThe candidate’s qualifier trigger condition was not satisfied for the user’s plan or category.
sdk_disabled_provider_failureThe SDK disabled itself after its configured providers failed, so it fails closed rather than risk showing something wrong.
segment_target_mismatchThe user doesn’t belong to any of the candidate’s target segments.
suppressed_by_dismiss_cooldownThe user dismissed this placement and its cooldown window has not elapsed.
suppressed_by_payload_cap_dayThe payload’s per-day impression cap has been reached.
suppressed_by_payload_cap_lifetimeThe payload’s lifetime impression cap has been reached.
suppressed_by_payload_cap_monthThe payload’s per-month impression cap has been reached.
suppressed_by_payload_cap_sessionThe payload’s per-session impression cap has been reached.
suppressed_by_payload_cap_weekThe payload’s per-week impression cap has been reached.
suppressed_by_payload_cooldownThe payload is still inside its configured cooldown window since it was last shown.
suppressed_by_presentation_capEvery eligible candidate is over an overall presentation cap rule from Placement Settings.
suppressed_by_system_cooldownEvery eligible candidate is a discretionary nudge inside the session cooldown since the last one shown.
suppressed_until_remind_windowThe user chose “remind me later” and that reminder window has not elapsed yet.
threshold_trigger_unmetThe candidate’s threshold trigger did not match the user’s current entitlement usage.
trial_trigger_unmetThe candidate’s trial trigger did not match the user’s trial state.

Returned in result.reason to explain the entitlement check outcome.

Entitlement checks are fail-closed: when the SDK cannot produce an affirmative grant it denies and names the cause. This is the complete emitted set — see Error handling for the enforcement-mode suffixes on the two limit codes.

CodeMeaningFix
no_matching_entitlement_ruleNo rule grants this entitlement to the user’s plan — check deniedAdd an entitlement rule targeting that plan, or check the user’s plan_handle is the plan’s unique_handle
feature_not_enabled_for_planA matching feature rule has enabled: false — check deniedEnable the rule for that plan, or upgrade the user
usage_limit_reachedAt or over a usage_limit rule’s limitReport accurate usage via updateUsage(); raise the limit or change enforcement
credit_balance_exhaustedAt or over a credits rule’s allowanceGrant more credits or change enforcement
config_unavailableThe launched Playbook could not be fetched (Server mode) — check deniedCheck network connectivity; the reason distinguishes a fetch failure from a real denial
entitlement_not_in_playbookLocal mode with no Playbook and no cached result — check deniedAdd the entitlement to the Playbook fixture
sdk_disabled_provider_failureThe SDK disabled itself after a provider failure — check deniedCheck API keys, endpoints, and network
granted_by_reverse_trialAllowed by an active reverse trial rather than by the planNone — expected during a reverse trial
ErrorSourceMeaning
provider_chain_exhaustedAll providers failedCheck API keys, endpoints, and network
config_fetch_failedPlaybook could not be loadedVerify configProvider or API endpoint
invalid_api_keyAPI returned 401Check the publicKey (browser) or apiKey (server) value and key status
tenant_not_foundAPI returned 404Verify tenantId value
ErrorContextMeaning
interaction_tracking_failedtrackTreatmentInteraction()Event delivery failed — silently dropped
event_delivery_failedtrackEvent()Custom event could not be sent — buffered for retry
network_errorInteraction-flush fetchThe touchpoint-transition request threw (offline, DNS, CORS) — the batch is re-queued and retried
ErrorContextMeaning
storage_unavailablelocalStorage/sessionStorageBrowser storage not accessible — using in-memory fallback
storage_quota_exceededsetItem() failedClear old entries or use custom storage provider

Enable verbose logging to see all reason codes and errors:

TypeScript
localStorage.setItem('revturbine:debug', 'true');

Errors and reason codes are also available programmatically:

React
const { decision, error } = usePlacement({ placement: { name: 'hero_banner' } });
// Hook-level error (string)
console.log(error);
// Decision-level reason codes
console.log(decision?.reasonCodes);