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 = nullView on GitHub (pinned to 1136503c6a)
Solutions
- Call snapshot() (or 'orca snapshot') before any ref-based command.
- Re-snapshot after any navigation (goto, link-click navigation, redirect).
- 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
- Always call snapshot() before any ref-based command (click, fill, hover, scroll).
- Re-snapshot after navigation, debugger detach, or any error that may have cleared the snapshot.
- In agent loops, snapshot once per page state and invalidate on navigation.
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
- browser_ref_not_found
- Missing ${ENTRY_PATH}; run pnpm run build:electron-vite firs
- No historical released snapshot is available for ${name}
- {action} is not a valid secondary action
- element value is not settable
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/c0ba11b4f68c17c8.
Report an issue: GitHub.