Skip to main content

Advanced Troubleshooting

This guide covers deep debugging across controller, relay, and extension node workflows. Start with the core workflow to isolate the failure layer, then use the error-to-action table to resolve it.

Core debugging workflow

  1. Reproduce with a fresh request — avoid debugging stale state.
  2. Collect broad logs — use --source all first to see all components.
  3. Isolate by requestId — use one request ID as the primary correlation key.
  4. Narrow the failure layer — auth, routing, execution, listener lifecycle, or cleanup.

Useful commands

GoalCommand
Follow all sources liveotto logs follow --source all
Focus extension-side runtimeotto logs follow --source node
Pull bounded node evidenceotto logs list --source node --latest 300
Verify command visibilityotto commands list
Reproduce with machine-readable outputotto test <site> <command> --json
Open a fresh managed tabotto cmd --action primitive.tab.open --payload '{"url":"https://example.com"}'

Error-to-action table

ErrorSymptomLikely causeResolution
manual_login_requiredCommand pauses, tab stays openBrowser session missing for siteLog in manually in the browser tab, then rerun the command
site_mismatchCommand rejected before executionTab URL does not match command siteNavigate to the correct host or reopen tab via primitive.tab.open
tab_url_not_readyCommand rejected at startupURL not committed to Chrome tab yetRetry after a short delay; use primitive.tab.open to mint a fresh session
acl_missing_node_grantNode-targeted command blockedController client lacks node ACL grantGrant access from the node ACL API or via otto client flow
tab_busy / tab_lockedCommand times out waiting for lockAnother command holds the tab lockRetry with bounded backoff, or configure wait_with_timeout wait policy
invalid_access_tokenAuth fails on every commandAccess token expiredRun otto client login to refresh tokens
forbidden_actionCommand rejected at relayController token lacks required scopeRe-register or refresh with wider-scope token
tip

For any failure, capture the requestId from the error envelope first. Then use otto logs list --request-id <id> --source all to see the full timeline across components.

Stream diagnostics

For stream failures, follow this isolation sequence:

  1. Confirm command.test returned stream.listeners in the result envelope.
  2. Verify subscribe command returned a terminal result (not an error).
  3. Confirm listener_update events correlate to the subscribe requestId (not the original command requestId).
  4. Verify teardown was explicit: listener.unsubscribe or command_cancel on the stream command.

For raw network capture validation:

otto listener subscribe-network \
--tab-session <tabSessionId> \
--site example.com \
--pattern 'https://api.example.com/*' \
--mode network

Expected: streamed listener_update events. If nothing arrives, the pattern, host, or mode may be misconfigured.

Prevention

  • Keep targetNodeId explicit on every command.
  • Use otto commands list before debugging execution failures — confirms auth and routing are healthy.
  • Refresh tokens proactively for long-running controller sessions.
  • Use --stream-follow-ms with a timeout for unattended stream tests instead of leaving sessions open indefinitely.

Next steps