ThinkRun

llms.txt

Error Codes

All API responses include structured error information. Use the code and retryable fields for programmatic error handling.

Response Format

Error responses follow this structure:

{
  "success": false,
  "error": "Element not found: button.submit",
  "code": "ELEMENT_NOT_FOUND",
  "hint": "Verify the selector exists. Try taking a snapshot first.",
  "retryable": true   // local/bridge mode only
}

Cloud mode includes hint. Local bridge mode includes retryable. Both include code.

Recorder plans and analysis errors

GET /api/credits/recorder-plans is public and returns the recorder-allowance-v1 Free and Pro plans with a mode. Mode is preview unless the server sets METER_ANALYSIS=1; only live means allowances are enforced, and enforcement also needs durable recording storage. Free: five successful cloud analyses per account, up to 120 seconds each. Pro: $19/month, 3,600 analyzed seconds per confirmed billing period, up to 900 seconds each. Storage caps (1 GiB, 20 GiB) follow the separate storage-accounting rollout. Browser credits are separate.

GET /api/credits/recorder-usage requires authentication and is private, no-store. It returns contract, mode, plan, unit, limit, used, reserved, remaining, maxAnalyzedSeconds, periodStart and resetsAt. Free counts analyses with null period fields; Pro counts seconds. remaining already subtracts in-progress reservations.

Analysis errors return success: false, status, code, error, jobId and optional limit and mode. Duration codes have status: "failed"; the others have status: "waiting". There is no retryable field, so treat the guidance below as advisory. The usage endpoint's 503 has only success, code and error. Successful upload completion returns HTTP 200 with success: true; inspect optional analysisWaiting.code for held analysis and preserve the uploaded recording.

CodeHTTPRecovery
RECORDER_DURATION_UNKNOWN422Do not resubmit the same media; its duration could not be verified.
RECORDER_DURATION_LIMIT422Use a shorter recording or a plan with a longer per-recording limit.
RECORDER_ALLOWANCE_EXHAUSTED402Free: upgrade. Pro: wait for the next confirmed billing period. Browser-credit top-ups do not restore it.
RECORDER_RESERVATION_LIMIT409Wait for an in-progress analysis to finish, then retry.
RECORDER_ENTITLEMENT_UNAVAILABLE503Retry later; plan or allowance state could not be verified.

Cloud API Error Codes

Source: error-handler.ts — shared by cloud session and recording routes

Storage accounting remains disabled pending release acceptance. Check recording state before retrying an uncertain upload.

CodeHTTPRetryMeaningHint
ELEMENT_NOT_FOUND404YESCSS selector matched nothingTake a snapshot to inspect the DOM
ELEMENT_IN_IFRAME404YESElement is inside an iframeUse a frame-aware selector
ELEMENT_IN_SHADOW_DOM404YESElement is inside a shadow DOMUse >>> shadow-piercing syntax
NAVIGATION_TIMEOUT504YESPage took too long to loadIncrease timeout or check URL
OPERATION_TIMEOUT504YESOperation exceeded time limitSimplify the operation or increase timeout
SESSION_CLOSED410FATALBrowser session was closedCreate a new session
PAGE_NAVIGATED409YESNavigation occurred during operationWait for navigation, then retry
BROWSER_PROTOCOL_ERROR502YESBrowser internal communication errorRetry or create new session
STORAGE_TIMEOUT503YESStorage backend slow or unreachableRetry in a few seconds
STORAGE_ERROR502YESStorage backend returned an errorUsually transient, retry
BROWSER_POOL_UNAVAILABLE503YESNo browser instances availableRetry in 10-30 seconds
SESSION_LIMIT_REACHED429YESMaximum concurrent sessions reachedDelete unused sessions first (DELETE /api/sessions/:id), or wait up to 30 min for idle sessions to auto-expire, then retry
PROVISIONING_FAILED503YESCloud machine provisioning failedRetry in 30 seconds
AUTH_SERVICE_UNAVAILABLE503YESAPI-key validation storage is temporarily unavailableRetry in a few seconds; your API key was not rejected
INVALID_API_KEY401NOAPI key invalid or expiredCheck or regenerate your API key
EVALUATE_FAILED400FATALJavaScript evaluation errorCheck script for syntax errors
PAYLOAD_TOO_LARGE413NORequest body exceeds size limitReduce payload size
INSUFFICIENT_CREDITS402FATALNot enough credits for this operationPurchase credits at /api/credits/checkout
WS_DISCONNECTED503YESChrome extension WebSocket disconnectedEnsure the extension is running and connected
CLI_TIMEOUT504YESServer-side CLI agent timed outTry a simpler task or increase timeout
CLI_FAILED502YESServer-side CLI agent process errorCheck server logs; agent exited non-zero
NETWORK_ERROR502YESTarget URL unreachableVerify URL is correct and accessible
STORAGE_CAP_EXCEEDED413NOStorage limit reached (storage preview)Delete recordings to free storage or upgrade before uploading
STORAGE_OWNER_REQUIRED403NORecording owner could not be confirmed (storage preview)Sign in to the recording owner account
STORAGE_UPLOAD_DECLARATION_REQUIRED400NOUpload length or checksum is invalid (storage preview)Correct the upload declaration before retrying
STORAGE_ACCOUNTING_UNAVAILABLE503NOStorage accounting could not confirm the upload (storage preview)Read current recording state; do not automatically resubmit
STORAGE_PROVIDER_IDENTITY_MISMATCH503NOProvider identity could not be confirmed (storage preview)Read current recording state; do not automatically resubmit
STORAGE_ACCOUNTING_CONFLICT409NORecording storage state changed (storage preview)Refresh the recording and resolve pending uploads before retrying
RECORDING_OWNERSHIP_DENIED409NORecording ownership changed or could not be confirmedRefresh the recording and confirm ownership before trying again
RECORDING_MUTATION_UNCERTAIN503NORecording update outcome could not be confirmedRead current recording state before retrying; never automatically resubmit
RECORDING_GUARDED_READ_FAILED503YESStorage preimage read failed; no update submittedRetry after storage recovers and confirm current recording state
RECORDING_STORAGE_UNAVAILABLE503YESAuthoritative recording metadata read is temporarily unavailableRetry GET with bounded backoff; inspect state before retrying a write. Cached state is not served during an outage.
ANALYSIS_SUBMISSION_RECONCILIATION_REQUIRED409NOAn earlier analysis submission must resolve before analysis or video can changeCheck analysis status and retry manually once the submission resolves; contact support if it persists
INTERNAL_ERROR500YESUnclassified server errorCheck server logs

Local Mode Error Codes

Source: local native host — run thinkrun attach <tabId> before issuing commands

CodeHTTPRetryMeaningHint
EXTENSION_NOT_CONNECTED503YESChrome extension is disconnected or still reconnectingIf the extension is not installed, open Chrome with ThinkRun. Otherwise wait briefly or run thinkrun doctor.
EXTENSION_DISCONNECTED503YESExtension disconnected mid-requestRun thinkrun doctor first. If the bridge is healthy, use thinkrun session debug --json for continuity details.
REQUEST_TIMEOUT504YESNative host request timed out (30s)Retry or check extension responsiveness
COMMAND_TIMEOUT504YESExtension command execution timed outSimplify the action or increase timeout
TAB_NOT_FOUND410FATALTarget tab was closed or the remembered local binding is staleRun: thinkrun tabs, then thinkrun attach <tabId> for a live tab
TAB_NOT_OWNED403FATALAgent session does not own this tabRun: thinkrun attach <tabId> to claim this tab
TAB_OWNED_BY_OTHER_SESSION403FATALAnother local session owns the tab, or the local authority cache is staleRun: thinkrun session debug --json first. If continuity is still yours, re-attach only to rebuild authority. If another live owner holds the tab, use thinkrun new-window or wait for release.
SESSION_NOT_FOUND404FATALAgent session ID not registered in native hostRun: thinkrun attach <tabId> to register a session
ELEMENT_NOT_FOUND404YESCSS selector matched nothingCheck selector against page DOM
NAVIGATION_FAILED502YESPage load failed (net::ERR_*)Verify URL is accessible
SCRIPT_ERROR400FATALJavaScript syntax or runtime errorFix the script
TASK_TIMEOUT—NOAI task exceeded configured timeoutIncrease --timeout or break the task into smaller steps
BRIDGE_UNREACHABLE—FATALLocal bridge could not be reached before the attach or switch request was issuedRun: thinkrun doctor
NATIVE_HOST_UNREACHABLE—FATALClient-side bridge route could not be reached after port revalidationRun: thinkrun doctor. If a mutating command was in flight, verify page state before retrying.
NATIVE_HOST_ERROR—FATALNative host bridge is not running or encountered a fatal errorRun: thinkrun doctor

Blank status cells on native-host bridge errors mean the CLI surfaced a structured local error before any HTTP response was produced.

Native-host self-install (thinkbrowse-host --install) returns a non-zero exit code on partial manifest-write failures so scripts can detect incomplete installs.

Fatal vs Transient Errors

The task executor uses a smart circuit breaker to distinguish fatal errors (stop immediately) from transient errors (retry with backoff). The native-host bridge has its own circuit breaker that opens after 3 consecutive non-app errors (e.g. command timeouts). If thinkrun doctor reports a circuit-breaker trip, run thinkrun reset-connection to re-arm it without reloading the extension.

Fatal (stop immediately)

2 consecutive fatal errors aborts the task.

  • SESSION_CLOSED — browser gone
  • TAB_NOT_FOUND — tab gone
  • TAB_NOT_OWNED — run attach
  • TAB_OWNED_BY_OTHER_SESSION — session debug before any re-attach
  • SESSION_NOT_FOUND — run attach
  • SCRIPT_ERROR — bad JavaScript
  • EVALUATE_FAILED — eval error
  • BRIDGE_UNREACHABLE — doctor before retrying attach, switch-tab, or focus
  • NATIVE_HOST_UNREACHABLE — doctor + verify page state before manually re-issuing mutating commands
  • NATIVE_HOST_ERROR — run doctor
  • INVALID_API_KEY — bad key
  • INSUFFICIENT_CREDITS — buy credits

Transient (retry with backoff)

5 transient errors within 60s aborts the task.

  • ELEMENT_NOT_FOUND — may appear during load
  • NAVIGATION_TIMEOUT — slow page
  • EXTENSION_NOT_CONNECTED — reconnecting
  • BROWSER_PROTOCOL_ERROR — transient
  • AUTH_SERVICE_UNAVAILABLE — retry; do not rotate the API key
  • HTTP 502, 503, 504, 524

Handling Errors Programmatically

# Check the code field in the response
RESP=$(curl -s -X POST "$BASE/api/sessions/$SID/click" \
  -H "x-api-key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"selector": ".nonexistent"}')

CODE=$(echo "$RESP" | jq -r '.code // empty')
case "$CODE" in
  SESSION_CLOSED|TAB_NOT_FOUND)
    echo "Fatal: session gone, create a new one" ;;
  TAB_NOT_OWNED|SESSION_NOT_FOUND)
    echo "Fatal: run thinkrun attach <tabId>" ;;
  TAB_OWNED_BY_OTHER_SESSION)
    echo "Inspect session debug first; same-lineage re-attach may still recover authority" ;;
  BRIDGE_UNREACHABLE|NATIVE_HOST_ERROR)
    echo "Fatal: run thinkrun doctor" ;;
  NATIVE_HOST_UNREACHABLE)
    echo "Fatal: safe reads already exhausted retries; run thinkrun doctor and verify page state before re-issuing mutating commands" ;;
  INVALID_API_KEY|INSUFFICIENT_CREDITS)
    echo "Fatal: fix credentials or buy credits" ;;
  SESSION_LIMIT_REACHED)
    echo "Delete unused sessions, then retry" ;;
  ELEMENT_NOT_FOUND|NAVIGATION_TIMEOUT)
    echo "Transient: retry after delay" ;;
  EVALUATE_FAILED|SCRIPT_ERROR)
    echo "Fatal: fix the script" ;;
esac

TAB_OWNED_BY_OTHER_SESSION is the main nuanced case in local mode: check thinkrun session debug --json first, because a same-lineage re-attach can recover local authority without taking over a foreign tab.