Skip to content

Troubleshooting

SymptomLikely CauseFix
getPlacement returns null unexpectedlySlot/component mismatch or no eligible payloadVerify slotId, componentType, and payload targeting. Start with createSlotPlacementRequest(...).
A slot renders nothing, with no error and no reason codeThe placement targets a slot your code never mounts — it can never showRun sdk.diagnoseSlotInventory(). Comparing slot ids by eye is what this replaces.
A slot renders its fallback foreverYour code mounts a slot no placement targetsSame probe — it reports this direction too.
Entitlement check denies with config_unavailable or sdk_disabled_provider_failurePlaybook fetch or configured provider failedVerify endpoint availability, auth headers, and provider health. See Client vs Server Enforcement for the authoritative fallback contract.
CTA path not firing expected actionPayload action field mismatch (cta_path vs legacy shape)Use canonical cta_path in payloads and parse via PlacementRenderer.
Decisions feel staleCache TTL too longLower ttlMs in decision requests or call refresh flows explicitly.
Interactions not visible in backend telemetryIngestion endpoint misconfiguredValidate ingestEvents/touchpointTransition endpoint wiring and auth.
Runtime mode behavior is incorrectWrong mode or incomplete mode configRe-check mode selection in the runtime modes guide and use mode helper builders.
Console warns primary provider failedThe provider chain is failing: entitlement checks deny with sdk_disabled_provider_failure and slots follow providerFailureSlotBehaviorConfigure providerFallbacks, verify provider health, and choose providerFailureSlotBehavior intentionally.
Type is unknown from SDK routeContract/schema title mismatchEnsure the SDK version matches the schema version and reinstall.
Build fails after SDK API changesMissing migration updates in caller codeMigrate to object-style request helpers and rerun typecheck.
Warning or reasonWhat to inspect
Blank user IDWait for authentication or intentionally omit user for a visitor; never pass an empty ID as a loading placeholder.
Email-shaped identityUse a stable internal user/account ID; keep email in its dedicated context field.
Dropped context keysUse the flat canonical UserContext shape; free-form targeting belongs under custom, not an extra context wrapper.
Missing UI-path resolverRegister the authored action type or remove the unused action. A tracked click alone does not navigate or open checkout.
entitlement_not_in_playbookCompare the exact handle with the loaded Playbook and confirm the correct tenant/version.
not_access_entitlement_kindprice_per_unit and rate_limit are parameter kinds; gate on an access entitlement.
config_unavailableDiagnose delivery/authentication/version admission; do not turn an unavailable policy into a paid grant.
VAL-PLN-07A numeric cap has no explicit enforcement choice. The default blocks at the cap. Choose hard_block, block_with_upsell, degrade, or allow_overage intentionally in the authored rule.
Playbook tenant_id differs from the SDK initialization target (for example, local)Check the imported artifact and the explicit tenantId option. For local input, the init target wins and a mismatch warns; align them with the intended tenant rather than suppressing the warning. This is not an instruction to rewrite a signed hosted artifact.
The server’s schema is newer than this CLI’s bundled snapshotOffline validation may lack newer rules. Update the repository’s pinned CLI (npm install -D @revturbine/cli@latest, or your package manager’s equivalent). The warning clears when that CLI’s bundled schema version is at least the server stamp; reinstalling the same version does not resolve the lag.

Read initStatus inside the actual provider and inspect getPlaybookLoadFailure() on an initialized SDK when delivery fails. A once-per-session warning may not repeat on every render; fix the cause and rerun the relevant transition. Do not disable validation globally to hide a warning. See identity lifecycle and SDK upgrades.

This is the hardest symptom to debug, because there is no error. Almost nothing in the SDK throws — a mismatch degrades instead of erroring — so a placement that can never show looks exactly like a user who is not eligible.

The usual cause is that a placement targets a slot id your code does not mount, or your code mounts a slot id no placement targets. Neither is visible from the Playbook alone: a config-side audit cannot see your call sites. Only the running app knows what it mounted, so ask it:

TypeScript
const diagnosis = sdk.diagnoseSlotInventory();
if (!diagnosis.configAvailable) {
// No Playbook reached the SDK. `authored` is empty for a completely
// different reason than "nothing is authored" — check this FIRST, because
// the two look identical in the lists below.
console.warn('No Playbook available; fix initialization before reading the rest.');
}
// Placements that can never show: they target a slot nothing renders.
console.log(diagnosis.authoredButUnmounted);
// Slots that render their fallback forever: nothing targets them.
console.log(diagnosis.mountedButUnauthored);

Each finding names the placement id and category, so it points at the thing to fix rather than telling you something is wrong somewhere.

If both lists are empty, configAvailable is true, targeting matches the user, and the placement still does not render — stop. That is a correct configuration producing silence, which is not a configuration problem. Open an issue with the diagnostics output above and the SDK version, rather than working around it.

Requires @revturbine/sdk 0.8.0 or newer.

When all configured providers fail for getPlacement, checkEntitlement, or identify, the SDK disables itself to avoid inconsistent behavior.

In this state:

  1. The SDK logs warning messages to the console.
  2. Placements render as hidden (invisible) or safe placeholders (placeholder) depending on providerFailureSlotBehavior.
  3. Entitlement checks return a denied result with sdk_disabled_provider_failure; see Client vs Server Enforcement for why checks and placements have different fallback behavior.
  1. Run API type checks:

    Terminal window
    pnpm typecheck:sdk-api
  2. Run web build:

    Terminal window
    pnpm build
  3. Validate SDK docs generation:

    Terminal window
    pnpm docs:sdk