n8n-io/n8n · critical · ConnectionLostError
Browser connection lost: ${reason}
Error message
Browser connection lost: ${reason} What it means
ConnectionLostError(this.disconnectReason) is thrown by getConnection() when this.state is null AND this.disconnectReason is set — i.e. the connection was previously live and dropped unexpectedly (the onDisconnect handler recorded the reason). This distinguishes an involuntary disconnect from a never-connected state.
Source
Thrown at packages/@n8n/mcp-browser/src/connection.ts:168
if (pending) await pending.close().catch(() => {});
if (!this.state) return; // already disconnected — idempotent
const { adapter } = this.state;
this.state = null;
this.disconnectReason = undefined;
try {
await adapter.close();
} catch {
// Browser may already be dead — that's fine
}
}
getConnection(): ConnectionState {
if (!this.state) {
if (this.disconnectReason) {
throw new ConnectionLostError(this.disconnectReason);
}
throw new NotConnectedError();
}
return this.state;
}
get isConnected(): boolean {
return this.state !== null;
}
async shutdown(): Promise<void> {
await this.disconnect();
}
getResolvedConfig(): ResolvedConfig {
return this.config;
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Call browser_disconnect to clear disconnectReason, then browser_connect to re-establish.
- Subscribe to disconnect events and proactively reconnect before issuing further tools.
- Inspect the reason (error.reason) to decide whether a retry is worthwhile (e.g. heartbeat_timeout may be transient).
Example fix
// before — tool call after silent drop
const conn = connection.getConnection(); // throws ConnectionLostError
// after — reconnect on detected drop
try { const conn = connection.getConnection(); }
catch (e) { if (e instanceof ConnectionLostError) { await connection.disconnect(); await connection.connect(); } } Defensive patterns
Strategy: try-catch
Validate before calling
if (!connection.isConnected) {
await connection.disconnect(); // clears disconnectReason
await connection.connect();
} Type guard
function hasDisconnectReason(c: BrowserConnection): boolean {
// disconnectReason is private; infer via isConnected + prior drop flag
return !c.isConnected && /* tracked externally */ dropped;
} Try / catch
try {
const conn = connection.getConnection();
} catch (e) {
if (e instanceof ConnectionLostError) {
await connection.disconnect();
await connection.connect();
} else throw e;
} Prevention
- Subscribe to onDisconnect and proactively reconnect.
- Clear agent-side connection assumptions on any disconnect event.
- Inspect error.reason to decide retry vs. surface-to-user.
When it happens
Trigger: Calling any tool that internally calls getConnection() after the adapter fired onDisconnect with a reason (browser_closed, extension_disconnected, debugger_detached, network_error, or heartbeat_timeout). The state was nulled by the disconnect handler but disconnect() was not explicitly called.
Common situations: User closed the browser mid-session. Extension service worker evicted. Debugger banner dismissed in Chrome. Any async tool firing after the disconnect event but before the agent calls browser_disconnect/browser_connect.
Related errors
- CONNECTION_NOT_FOUND
- SPECIFIC_CONNECTION_NOT_FOUND
- Browser connection lost: The browser extension disconnected
- Browser connection lost: The connection to the browser exten
- Already connected to a browser
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/d2f761f42d20cb06.
Report an issue: GitHub.