Foundation / Getting Started
Common SDK setup failures and the fastest path to resolve them.
Browse Documentation
Foundation
Platform
Capabilities
Product
Core Platform
Core Platform
Developers
Operations
Business
Billing and Plans
Billing and Plans
On This Page
No section anchors
# Troubleshooting
Use this page when the SDK is installed but your protected route is still not behaving correctly.
## Missing API Key
- Symptom: SDK calls fail before the request is sent or return auth errors.
- Check that COSANTOIR_API_KEY is set and scoped to the module you are calling.
- Runtime integrations should prefer API keys over bearer tokens.
## Missing Site Id
- Symptom: bearer-auth calls fail or the request cannot be mapped to policy.
- Set COSANTOIR_SITE_ID on the client or on the adapter options.
## Missing Client IP
- Symptom: middleware throws a configuration error about IP resolution.
- Forward cf-connecting-ip, x-forwarded-for, x-real-ip, or supply an explicit resolver.
## Unexpected 429 Responses
- Check Retry-After and the X-RateLimit-* headers.
- If the error payload includes quota_exceeded with exhaustedDimension=monthly_budget_cap, the workspace has either already hit its monthly runtime budget cap or the next exact billable request would cross it.
- Check the dashboard billing card for the next frontend and backend request estimates before retrying production traffic.
- Raise the budget cap or wait for the next billing period before expecting production API-key traffic to succeed again.
- Check x-dev-billing-cache to see whether the runtime used a fresh, cached, stale, or bypassed billing access lookup.
- Check x-dev-replay-status to confirm you are not debugging a replayed response.
- Inspect the active route key and burst policy for the path that is blocking.
- Confirm that local test traffic is not reusing the same IP bucket.
## Unexpected 403 Responses
- Check whether WAF returned block or challenge.
- Inspect the matched rule id, rule type, and reason in the response body.
- Verify whether the request path or user agent is hitting a custom expression or managed rule.
## Unexpected 401 Responses
- Check whether the caller sent x-api-key or Authorization: Bearer ... at all.
- Invalid and expired bearer tokens are now tracked in the dashboard's runtime auth-failure section instead of the decision log.
- Invalid API keys and missing credentials are tracked there too, even when the runtime never resolved a site.
- If a valid API key now points to a deleted or unavailable site, the auth-failure view will show api_key_site_unavailable.
- Narrow the runtime auth-failure stream with auth_type and failure_reason filters before exporting for support or incident handoff.
- Export the current workspace or site scope from the dashboard, or call GET /v1/dev/runtime-auth-failures/export?format=csv|jsonl for operator handoff.
- The dashboard also derives operational alerts for sudden auth-failure spikes, repeated missing credentials, and api_key_site_unavailable regressions.
- You can now route those alerts to generic signed webhooks, Slack incoming webhooks, or PagerDuty Events v2 from the runtime auth-failure panel.
- Generic webhooks expose a one-time signing secret and send x-cosantoir-signature; Slack incoming webhooks do not use that secret or expose rotate-secret controls.
- PagerDuty Events v2 destinations store only a routing-key hint in the console and require the official /v2/enqueue endpoint.
- The notification panel also keeps recent configuration history so you can confirm who created, edited, rotated, archived, or switched provider types on a destination.
- Configuration history can be filtered by action and provider type, then exported as CSV or JSONL for incident review or change tracking.
- Those configuration-history filters persist in the dashboard URL, and you can save them as workspace or site-scoped presets for repeat investigations.
- Saved presets can now be edited in place and given an explicit display order, so the incident-review views you use most stay pinned to the top of the panel.
- Workspace presets and site-only presets now reorder independently, so changing one site's incident-review order does not reshuffle the workspace defaults.
- The dashboard URL also persists project_id, site_id, auth_type, and failure_reason, so a shared incident link can reopen the same selected site and auth-failure slice.
- Internal dashboard navigation now preserves that query state, so switching tabs or opening settings keeps the same project, site, and auth-failure context.
- Shared dashboard links can now also target requests_module and analytics_panel, so operators can reopen the same runtime control-room section or analytics cluster after a refresh.
- When a shared link pins project_id or site_id, the header exposes a reset action that clears only that control-plane context and keeps the current view, focus, and filters intact.
- Billing and app-creation flows can now be reopened from a shared dashboard link with modal=payment or modal=app, while the rest of the dashboard context stays intact.
- When those modals are opened from inside the dashboard, they now create a browser-history entry so close actions can behave like a real back navigation instead of flattening the session.
- Runtime API key issuance now adds api_key_secret=<key_id> to the dashboard URL for recovery, but the plaintext secret stays only in same-session browser storage so a copied link does not leak the secret itself.
- If that recovery link is opened after the same-session storage is gone, the keys page now tells the operator to revoke and reissue instead of pretending the one-time secret is still retrievable.
- Generic notification destinations now do the same through notification_signing_secret=<destination_id>, so secret rotation or webhook creation can survive a refresh without exposing the signing secret in a shared link.
- If that notification recovery link outlives the same-session storage, the dashboard now tells the operator to rotate the signing secret or recreate the generic destination instead of implying the plaintext secret can still be fetched.
- Stale policy-save conflicts now also persist a policy_conflict=<reference> state in the dashboard URL, while the stale draft itself stays only in same-session browser storage.
- The rules view now opens a merge workbench that highlights schema drift plus changed, current-only, and stale-only modules before you restore the stale draft.
- Each changed shared module now also shows field-level drift and a patch preview, so you can see exactly which keys changed, only exist on the current head, or only exist in the stale draft.
- Use the apply-selected-fields action to merge only the stale paths you intend to keep.
- That means a refresh can still reopen the conflict panel and restore the stale draft for manual merge, but a copied link does not expose the policy JSON itself.
## No Decisions In The Dashboard
- Confirm that the SDK is pointing at the correct COSANTOIR_GATEWAY_URL.
- Confirm that COSANTOIR_SITE_ID matches the site selected in the dashboard.
- Verify that the route is actually calling the SDK middleware or handler path.
- Billing-access and monthly-budget preflight denials are logged once the runtime can resolve the site, so those failures should still appear in decisions and analytics.
- For invalid credentials before site resolution, check the runtime auth-failure analytics panel instead of the decision log.
- If you are load testing with idempotency enabled, confirm the request key is not replaying the same decision intentionally.
## Runtime Policy Or Replay Headers
- x-dev-policy-cache=hit means the runtime used an in-process cached policy head.
- x-dev-policy-cache=stale means the runtime served the most recent cached policy after a refresh failure.
- x-dev-billing-cache=bypass means the request did not require a production API-key billing lookup.
- x-dev-billing-cache=hit means the runtime reused a cached workspace billing-access snapshot.
- x-dev-billing-cache=stale means the runtime served the most recent cached billing-access snapshot after a refresh failure.
- x-dev-replay-status=bypass means no idempotency key was supplied for the request.
- x-dev-replay-status=replayed means the runtime returned the original response and skipped duplicate writes.
- 409 idempotency_conflict means the same idempotency key was reused with a different payload.
- Once the runtime has already resolved the site and active policy head, idempotency_conflict is also written into the developer decision log as a non-billable block event.
- 503 policy_unavailable means the runtime could not load an active policy and had no stale cache entry to fall back to.
- policy_unavailable is also written into the decision log when site context exists, but its policy version fields are null because the runtime could not honestly resolve an active policy head.
## Next.js Quickstart Returns 503
- The apps/developer Next.js quickstart route requires DEVELOPER_RUNTIME_API_KEY and DEVELOPER_RUNTIME_SITE_ID.
- Without those values the proxy fails open and the quickstart route reports missing configuration.