Reference

MCP Error Codes: Causes and Fixes

When a Rindler MCP tool call fails, the server returns a stable machine-readable error code beside a human-readable message telling you what to do next. Branch on the code, never on the message text. Many errors also attach a structured payload (error_data or data) with fields like retry_after_seconds, transient, valid_values, or param; read it before retrying. Every code the server can return is below, with its cause and the fix.

Map-acceptance verifier errors

This internal lane evaluates frozen mapping candidates and never expands their capabilities.

CodeCauseWhat to do
capability_not_acceptedThe verifier rejected a capability outside the frozen safe public-read cell set; no browser action ranFix or remap the candidate, freeze a new candidate, and verify again
invalid_paramsThe server could not bind the action's effective parameters to immutable execution evidence; no browser action ranCorrect the candidate's parameter shape, freeze it again, and re-run verification
map_acceptance_budget_exhaustedThe claimed run reached its hard session, dispatch, or per-cell attempt limit; no additional browser action ranFix runaway chain planning or the stuck cell before claiming a new run

How Rindler reports errors

The session tools (start_session, dispatch_action, close_session, await_auth) return a structured error object (stable code plus message) flagged as a tool error. Two exceptions mean the error flag alone is not a reliable branch point:

  • A dispatch_action failure that carries a diagnostic tree or safety-net suggestion but no structured error data returns as a normal, non-flagged result; act on the tree.
  • memory and manage_cookies never flag errors. They return an ordinary memory or cookie_manager screen carrying an error object with the code and message.

extract_document returns a compact JSON body:

{"error_code": "not_a_pdf", "error": "document: malformed or unreadable PDF"}

Codes are stable, messages are not ("Prose changes; codes do not."). One convention runs through the catalog: a code that says a session, sign-in, or config is gone means start over with start_session; a code that says the page is loading or blocked means stay on the same session and fix the immediate obstacle. unsupported_site is a screen value on a successful start_session, not an error code (see the last section).

Session and capacity errors

From start_session, close_session, await_auth, and the session checks inside dispatch_action.

CodeCauseWhat to do
invalid_urlurl is missing, does not parse, or has no extractable domainPass a full absolute URL
rate_limited_burstToo many start_session calls for the same site in a short window; error_data.retry_after_seconds is setReuse the session you already have; a working session needs no restart
session_limit_reachedServer is at concurrent-session capacityBack off for retry_after_seconds and retry; close_session on sessions you are done with
local_provider_unavailableBrowser pool is recovering (transient)Retry after the suggested delay; do not retry-storm
tier3_tunnel_unavailableSite needs a connected tunnel daemon and none is attachedSurface it to the user; retrying will not help until a tunnel connects
site_config_lookup_failedConfig DB lookup failed transiently during start_session, returned instead of unsupported_site so a timeout is not read as permanentRetry start_session
session_errorSession creation or resolution failed; data.cause classifies it (timeout, browser_provisioning_failed, page_init_failed, unknown), all transientWait and call start_session again
navigation_errorBrowser could not navigate to the URLRetry once; confirm the URL loads for a signed-out visitor
session_expiredThis browser session is no longer activeDo not retry this session_id; start_session for a fresh one, then re-issue the action with the new id
missing_session_idCall omitted session_idPass the id from start_session
unknown_sessionawait_auth got a session id that is not active for this userStart a new session
no_session_managerNo active session manager on the serverTreat as a transient server condition and retry
site_unresolvedawait_auth could not resolve which site the session belongs toStart a new session on the site URL
seal_read_failedInternal read failure inside await_authRetry once, then re-run the sign-in handoff
encode_failedInternal encode failure inside await_authRetry once, then re-run the sign-in handoff
internal_errorUnexpected internal errorRetry; if it repeats, open a fresh session

Screen and action validation errors

dispatch_action validates before it touches the browser, so these mean nothing ran on the page.

CodeCauseWhat to do
missing_actionCall omitted the action parameterPass action
invalid_actionAction is not valid on the current screen; the message lists the screen plus the Available and Global actionsPick from that list; the latest response is authoritative
unknown_actionAction name is not in the site config at all, usually invented or staleOnly dispatch names from the most recent response
unsupported_actionKnown placeholder that is not supported on this siteTreat the capability as absent and tell the user
action_disabledSite owner turned this action offDo not retry; report it
action_not_applicableThe action's declared field is absent on this page variant, common on multi-tenant Lever or Workday formsTreat it as a no-op, not a failure, and continue
action_chain_unavailableA saved Action Chain alias could not resolve, or its parameters were wrong (chains take exactly one string parameter, no attachments)Dispatch the underlying actions directly
no_site_configSession has no site domain or no loaded configCall start_session with the site URL first
already_authenticatedCredential login dispatched on a session already signed inSkip the login and proceed with the task
action_policy_unavailableSite owner's action policy could not be read (transient; nothing ran)Retry
invalid_filterA job-board filter value was rejected; error_data may carry the accepted valuesRe-read the valid values and re-dispatch
adapter_errorA site adapter could not build structured screen dataRetry; if it persists, read the screen with extract_content

Parameter errors

Most are your agent's inputs, fixable by retrying with corrected parameters. record_too_large and window_error are server-side exceptions.

CodeCauseWhat to do
unsupported_paramA parameter is not in the action's supported listDrop it
invalid_param_valueAn enum-constrained value is outside the accepted set; error_data.valid_values lists all. Also fires when dismiss_dialog gets an unusable button_textPick from valid_values and re-dispatch
missing_required_paramA required parameter the action interpolates is absent; error_data.param names itRe-dispatch with the parameter set
invalid_param_formatA value fails the action's declared format; the message includes an example when one exists (dates are normalized first)Reformat like the example and re-dispatch
invalid_offsetA list-window offset is negative or past the current extracted totalStart at 0, then pass next_window.next_offset exactly; if the page changed, restart from 0
record_too_largeOne extracted listing or product exceeds the record-window byte budget by itselfNarrow the page or report the oversized record; increasing limit will not help
window_errorServer could not apply or encode a list windowRetry once; if it repeats, report the failure
device_relay_param_invalidA device-relay login accepts only declared, non-sensitive parameters; credentials are entered on the paired device, never passed through the tool callPass only the declared parameters

Authentication errors

CodeCauseWhat to do
auth_requiredThe action needs sign-in and the session is unauthenticated, the stored sign-in was forgotten, or a one-time code must be entered in the hosted Rindler formRead auth_context and follow its lane. credential_prompt: collect the listed credential parameters and dispatch the credential action. remote_browser: share capture_url with the user, then call start_session again with no session_id once they finish (each capture_url expires in 15 minutes; use the newest). On a checkout or payment auth_required, reuse context.cart_items in the same response instead of re-navigating
auth_state_unavailableServer could not verify the stored sign-in state; no browser action ranRetry; if it persists, re-authenticate through a fresh start_session
device_relay_action_invalidSession selected device relay and cannot dispatch a non-relay credential loginUse the sign-in lane the session advertised
device_relay_not_admittedA device-relay action was dispatched on a session not admitted for relayStart a new session and use the advertised sign-in lane
device_relay_requiredcapture_auth was dispatched on a session whose login comes from the paired device, so there is no hosted browser to open; the message lists the relay login actionsDispatch one of those relay login actions instead
device_relay_selection_failedDevice relay could not bind while the session started; the session was closed (transient)Call start_session again

Execution and page-state errors

These fire after the browser ran the action; the server classifies the failure so you get a diagnosis.

CodeCauseWhat to do
execution_failedDefault when every transport failed with no more specific classificationRetry once or read the screen with extract_content; a transient failure is not a reason to abandon the site
execution_errorWorkflow failed with an internal error after all transports were exhaustedRetry; if it repeats, open a fresh session
build_errorServer could not build the workflow steps for this action (config-side defect)Report it; this is not an input problem
captcha_requiredA CAPTCHA blocks the action and the worker could not clear itShare capture_url so the user solves it in a hosted browser; the captured session is reused on the next action
bot_wall_compatSite served a browser-compatibility wall; bot evasion is managed for youRetry later or report the block; nothing to tune on your side
blocked_by_dialogA modal dialog covers the page; error_data carries dialog_title, dialog_buttons, and dismiss_candidatesCall dismiss_dialog with button_text from dismiss_candidates, then retry the same action on the same session; never abandon the session to escape a dialog
page_loadingPage has not finished renderingWait a few seconds and retry the same action; do not start a new session
post_action_check_failedAction ran but its declared success condition did not hold, so the screen did not advanceRead the current screen, adjust, and retry
mutation_precondition_failedThe action's write precondition could not be verified immediately before input, so the mutation was NOT attempted (error_data carries mutation_replayed: false, input_attempted: false, and a reason)Nothing was written, so this is safe to retry: re-read the screen to confirm the current state, then re-dispatch
write_transport_blockedThe site refused the write after the control was actuated and Rindler did not replay itDo not repeat the mutating action; first verify current site state with a read action, and if the write is absent, recover the browser/egress or CAPTCHA lane, then retry only as a new explicit dispatch

Site configs can also define their own patterns that set a config-specific code with a reset screen, so you may occasionally see a code specific to one site; treat its message as authoritative for the next step.

Dialog dismissal errors

dismiss_dialog is deliberately conservative: it only clicks controls that get past a dialog.

CodeCauseWhat to do
no_dialog_openNo blocking dialog to dismissRe-read the screen; the obstacle is something else
dialog_button_not_foundThe requested button_text is not on the open dialogUse one of the dismiss_candidates from the blocked_by_dialog error
unsafe_dialog_buttonTool refused the button; it will not click controls that spend money or remove itemsPick a safe dismiss control; route purchases or deletions through the site's real actions

Download errors

Some actions capture a file server-side (a CSV or PDF export). On success the response's data.download object carries the link, which expires in about 30 minutes.

CodeCauseWhat to do
download_capture_failedThe action triggered the download in the remote browser but the file could not be retrieved or deliveredDo not claim success or tell the user to check their downloads folder; report the failure with the error and offer to retry
download_capture_unsupportedFile capture is not supported on the lane this action executed throughNever claim success

Document errors (extract_document)

extract_document reads linked PDFs anonymously and sends no cookies, so it reads only what a signed-out visitor could.

CodeCauseWhat to do
not_a_pdfURL served HTML or a corrupt file, often a 404 pageVerify the link points directly at the PDF
pdf_no_text_layerScanned-image PDF with no selectable text (needs OCR)Say so rather than retrying
document_too_largeFile exceeds the fetch size limit (25 MiB by default)Cannot be read through this tool; find a smaller source
fetch_failedNon-2xx response, commonly a login-gated or moved PDF (the fetch is anonymous)Confirm the URL is publicly reachable
invalid_page_selectorRequested pages do not exist or the selector does not parseRetry with a valid selector; use the reported page_count to bound the range
unsupported_schemeOnly http and https URLs are supportedUse an http or https URL
blocked_hostRefuses to fetch private or reserved addressesUse a public URL
document_read_failedAny other failure, including reader initializationRetry once, then report
invalid_argumentextract_document was called without a urlPass url

Scope, config, and approval errors

These enforce whose config, whose site, and whose approval govern a call.

CodeCauseWhat to do
site_scope_deniedA site-scoped credential acted, navigated, or fetched outside its authorized site, or the site redirected off the authorized domains; the session is closed mid-action. Also fires on extract_document for an unbound URLStay within the authorized site; cross-site work needs a normal user token
config_not_trackedShared site config is not in your tracked runtime setAdd it in the dashboard, or switch catalog access to All shared configs
config_policy_unavailableRuntime config policy could not be read (transient; no session created or session closed)Retry shortly
config_access_changedShared-config access changed while the session was starting or running; the session was closedReview the dashboard selection and start a new session
config_acceptance_invalidThe site config resolved, but its map-acceptance proof is missing or was invalidated by a config changeNot retryable: the config must be re-accepted before sessions can start
workspace_deactivatedThe workspace has been deactivated by a Rindler admin, so no sessions can start and no config resolvesNot retryable; contact Rindler support to reactivate the workspace
connect_admission_blockedOn a Connect-enforced site, a mutation or download has no governed integration (reads always admit)Report the refusal reason from the message
escalation_requiredA fleet Cell tried a state-changing action, or any synthesized dynamic tool, and it routed to one-way human approval (marked an error so it is not retried)Wait for the human decision; do not re-dispatch
capability_not_permittedThe workspace's permission rules set this capability to Never allow, so the action was refused before anything ran; error_data carries the capability, a plain-language capability_reason, and capability_certain: false when the action could not be classified and fell back to the strictest matching ruleDo not retry; report the reason. A workspace owner or admin changes it under Permissions
approval_deniedMerchant approval gate paused a flagged mutating action and the approver denied it; error_data.approval_request_id identifies itDo not retry; report the denial
approval_timeoutThe approval request expired unansweredAsk the approver to act, then re-dispatch to open a new request
approval_check_failedGate could not read policy or record the request (transient)Retry
device_policy_unavailableWorkspace custody-device policy could not be read before a mutation, so nothing ranRetry; if it repeats, report the policy-read failure
device_actor_unavailableA custody-device rule applies, but the request has no trusted action actor, so nothing ranRe-authenticate through a caller that stamps the real workspace actor; do not retry unchanged
device_requiredWorkspace policy requires the action actor's custody device for this action class, but no device is connected, so nothing ranConnect that actor's custody device, then retry
mutation_precondition_failedA mutating action's write precondition did not hold, so the mutation was never attempted; error_data carries mutation_replayed: false, input_attempted: false, and a reasonRead reason, fix the precondition, then re-dispatch; the write did not happen, so this is safe to retry once corrected

Things that look like error codes but are not

A few names show up near errors without being machine-readable error_code values. Do not branch on them as codes.

  • unsupported_site is a screen. With no config, start_session returns screen: "unsupported_site", supported: false, and empty actions. With intent: "login" the same response can still include a capture_url for a hosted remote-browser sign-in, so only an unsupported_site response with no capture_url means the site is genuinely unavailable.
  • auth_status: "expired" is a response field: a saved login expired. Do not retry the same session; re-authenticate through the lane auth_context indicates, then call start_session again.
  • page_stuck is a boolean response field (and a safety-net trigger) set when the URL has not changed across several consecutive actions; it arrives on otherwise-successful responses.
  • error_code fields in server logs and telemetry duplicate codes already returned to the agent; they are not separate codes.
  • The dashboard HTTP API returns the string unsupported_site as an HTTP 404 body on one route; that is not an MCP error code.
  • extract_content returns structured list-window codes, but its auth failures still carry an auth_required: or auth_state_unavailable: prose prefix. get_auth_url, synthesize_schema, and fleet_status also return prose errors without machine codes.