stablyai/orca · warning · BrowserError

browser_stale_ref

browser_stale_ref

Error message

No snapshot exists for this tab. Run 'orca snapshot' first.

What it means

Element-ref commands (click, fill, hover, scroll, etc.) call resolveRef() which requires a prior accessibility snapshot to map element refs to CDP backendNodeIds. If state.snapshotResult is null, no snapshot has been taken for this tab, or a previous snapshot was invalidated (by navigation, debugger detach, or a stale-ref clear). Without a refMap, the command cannot resolve which DOM node to act on. The message tells the user to run 'orca snapshot' first.

Source

Thrown at src/main/browser/cdp-bridge.ts:1352

        })
      ])
    }
  }

  private senderForRef(guest: Electron.WebContents, ref: RefEntry): CdpCommandSender {
    return ref.sessionId ? this.makeCdpSender(guest, ref.sessionId) : this.makeCdpSender(guest)
  }

  private async resolveRef(
    guest: Electron.WebContents,
    sender: CdpCommandSender,
    ref: string
  ): Promise<RefEntry> {
    const tabId = this.resolveTabId(guest.id)
    const state = this.getOrCreateTabState(tabId)

    if (!state.snapshotResult) {
      throw new BrowserError(
        'browser_stale_ref',
        "No snapshot exists for this tab. Run 'orca snapshot' first."
      )
    }

    const entry = state.snapshotResult.refMap.get(ref)
    if (!entry) {
      throw new BrowserError(
        'browser_ref_not_found',
        `Element ref ${ref} was not found. Run 'orca snapshot' to see available refs.`
      )
    }

    // Why: iframe refs use a child session with independent nav history, so a parent-navId check would falsely reject them.
    if (!entry.sessionId) {
      const currentNavId = await this.getNavigationId(sender)
      if (state.navigationId && currentNavId !== state.navigationId) {
        state.snapshotResult = null

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Call snapshot() (or 'orca snapshot') before any ref-based command.
  2. Re-snapshot after any navigation (goto, link-click navigation, redirect).
  3. Re-snapshot after recovering from a browser_debugger_detached error.

Example fix

// before
await bridge.click('btn-submit')

// after
await bridge.snapshot()
await bridge.click('btn-submit')
Defensive patterns

Strategy: validation

Validate before calling

// CdpBridge doesn't expose snapshotResult publicly; callers should track snapshot state
let hasSnapshot = false
await bridge.snapshot()
hasSnapshot = true
// before any ref-based command:
if (!hasSnapshot) { await bridge.snapshot() }
await bridge.click(ref)

Try / catch

try {
  await bridge.click(ref)
} catch (e) {
  if (e instanceof BrowserError && e.code === 'browser_stale_ref' && /No snapshot/.test(e.message)) {
    await bridge.snapshot()
    await bridge.click(ref)
  }
  throw e
}

Prevention

When it happens

Trigger: Calling click(ref) or fill(ref, value) before calling snapshot(); after a navigation that cleared the snapshot; after a debugger detach that nulled snapshotResult.

Common situations: Agent skips the snapshot step; snapshot was cleared by Page.frameNavigated and the agent retries a ref-based action without re-snapshotting; fresh tab with no snapshot yet.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/c0ba11b4f68c17c8. Report an issue: GitHub.