Reference

Error codes

Typed errors on the stream and what to do about them.

Errors arrive as a typed error event with a retryable flag; the SDK maps each to a themed state. HTTP-level failures before the stream opens use the same codes in a JSON body.

CodeMeaningWhat to do
invalid_keyUnknown or revoked publishable keyCheck the key and environment. A key that is not rd_pk_… (or nc_pk_…, from before the rename) disables the copilot at init, and RendelLauncher renders nothing while it is uninitialised.
quota_exceededMonthly conversation cap reached, or app suspendedCheck the cap on the app's Settings page, and email us to raise it or upgrade the plan.
rate_limitedPer-device or per-user message limit hitBack off; limits are configurable per app.
model_busyUpstream model briefly over capacityRetry with backoff. The thread shows a one-tap Retry; nothing is re-sent automatically.
manifest_unknownServer has not seen this manifest hashCall Rendel.registerAction again, or restart the app, to re-sync the manifest.
upgrade_requiredThis build is below the minimum SDK version the server will serveTell the user to update the app. The floor is empty by default and stays empty unless a protocol break makes an old client actively wrong; see Changelog and versioning.
(device-side)Anything the SDK could not tell you on the wirePass RendelConfig(onLog: ...) and every handler failure, handler timeout, context-provider timeout, manifest rejection and transport error arrives as an RendelLogRecord with a stable code. Point it at your crash reporter.
invalid_requestMalformed request body, or a refused identity verification on /v1/identify (HTTP 403)For chat, almost always an SDK bug; for identify, check the HMAC is a lowercase hex HMAC_SHA256(userId, secret).
internalUnexpected server errorRetry; persistent failures show a themed unavailable state.

A retry resends the original request unchanged, turn_id included, so the server recognises it and neither writes the user's message twice nor bills for it twice. A dropped stream surfaces as a retryable error with a one-tap Retry, and any block the server announced but never completed settles to its fallback_text rather than pulsing forever. A turn that connects and then stalls is abandoned after RendelConfig.streamIdleTimeout (45 seconds by default) so the composer is never left disabled. A turn that connects, completes and produces no blocks at all is reported the same way ("No answer came back. Try again."), because a silent thread is indistinguishable from one still thinking. There is no gap detection: a frame the SDK cannot parse is skipped and nothing re-fetches it, so history convergence is not automatic yet.

The request id

Every turn carries one. It arrives on turn.start as request_id, comes back on the response as the X-Request-Id header, and prefixes every server log line for that turn. The SDK holds the most recent one on the controller and includes it in the records it sends to RendelConfig.onLog, so a crash report already carries it.

It resolves to one turn: what was asked, what was rendered, which actions ran and what the server was doing at the time. Paste it into the search on Conversations in the console and you land on that turn yourself; send it to us and we see the same one. If your own stack already traces requests, send X-Request-Id on the chat call and we will use yours instead of minting one.

On this page