musistudio/claude-code-router · error · Error
This browser automation session is observeOnly and cannot mu
Error message
This browser automation session is observeOnly and cannot mutate browser state.
What it means
Thrown by assertCanMutate when a tool that changes browser state (navigate, close tab, click, type, etc.) is invoked with a session whose observeOnly flag is true. Observe-only sessions are limited to read-only operations like snapshots and screenshots by design.
Source
Thrown at packages/electron/src/main/browser-automation-mcp.ts:1246
return existing;
}
const state = builtInBrowserService.getAutomationState();
if (!state.tabs.some((tab) => tab.id === ref.tabId)) {
throw new Error(`Browser automation session tab was not found: ${ref.tabId}`);
}
const restored: AttachedSession = {
attachedAt: Date.now(),
leaseId: randomUUID(),
observeOnly: false,
ref
};
this.sessions.set(ref.sessionId, restored);
return restored;
}
private assertCanMutate(session?: AttachedSession): void {
if (session?.observeOnly) {
throw new Error("This browser automation session is observeOnly and cannot mutate browser state.");
}
}
private removeSessionsForTab(tabId: string): void {
for (const [sessionId, session] of this.sessions) {
if (session.ref.tabId === tabId) {
this.sessions.delete(sessionId);
}
}
for (const [subscriptionId, subscription] of this.subscriptions) {
if (subscription.ref?.tabId === tabId) {
subscription.unsubscribe();
this.subscriptions.delete(subscriptionId);
}
}
}
private subscribeEvents(args: Record<string, unknown>): unknown {View on GitHub (pinned to 99f24806c6)
Solutions
- Attach a non-observe-only session (observeOnly: false / omitted) for mutating operations.
- Split your workflow: read via the observe-only session, mutate via a full session.
- Check the session's observeOnly flag before dispatching mutating tools.
Example fix
// before
const { session } = await call("browser_attach", { tabId, observeOnly: true });
await call("browser_navigate", { url, session });
// after
const { session } = await call("browser_attach", { tabId });
await call("browser_navigate", { url, session }); Defensive patterns
Strategy: validation
Validate before calling
if (session.observeOnly && MUTATING_TOOLS.includes(toolName)) { const { session: rw } = await call("browser_attach", { tabId: session.ref.tabId }); session = rw; }
await call(toolName, { ...args, session }); Type guard
function isMutableSession(s: { observeOnly?: boolean } | undefined): boolean { return !s?.observeOnly; } Try / catch
try { await call(toolName, args); } catch (e) { if (e instanceof Error && e.message.includes("observeOnly")) { /* attach a non-observe-only session and retry */ } else throw e; } Prevention
- Attach read-write sessions for action workflows
- Keep observeOnly strictly for monitoring
- Check flags before dispatching mutating tools
When it happens
Trigger: Calling a mutating tool (e.g. browser_navigate, browser_tab_close) with a session that was attached with observeOnly: true.
Common situations: A monitoring/audit integration intentionally attaches read-only but a later step tries to act; the observeOnly flag defaulted on unexpectedly in session setup.
Related errors
- browser_tab_activate requires tabId or session.
- browser_tab_close requires tabId or session.
- browser_navigate could not resolve an active tab.
- Chrome login import job was not found: ${jobId}
- Unknown browser automation tool: ${name}
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/dcfb0a37d2008828.
Report an issue: GitHub.