-
-
Notifications
You must be signed in to change notification settings - Fork 52.5k
Description
GitHub Issue Draft: Chrome Extension Relay Disconnects
Repo: https://github.com/openclaw/openclaw
File: Post as a new issue
Title
Chrome extension relay: frequent disconnects require manual re-attach (fixable in background.js)
Labels
bug, browser, extension
Body
Problem
The Chrome extension relay (background.js) disconnects frequently during normal use. The user attaches a tab via the toolbar button, uses it successfully, then minutes later the agent gets "tab not found (no attached Chrome tabs for profile 'chrome')." The user must manually re-click the toolbar icon to reattach.
This happens mid-workflow — e.g., agent navigates to site A successfully, then a few minutes later tries to navigate to site B and the connection is gone.
Environment
- OpenClaw 2026.2.9
- Brave Browser (Chromium-based, supports chrome.debugger)
- macOS 15 (Apple Silicon)
- Extension loaded unpacked via
openclaw browser extension install
Root Cause Analysis
After reviewing background.js, three issues cause the disconnects:
1. WebSocket drop nukes all debugger sessions (lines ~105-120)
onRelayClosed() calls chrome.debugger.detach() on every attached tab and clears all state when the relay WebSocket drops. Any transient WebSocket hiccup (network blip, service worker restart) destroys all debugger sessions even though the debugger attachment itself was fine.
// Current behavior — relay drop = detach everything
function onRelayClosed(reason) {
relayWs = null
// ...
for (const tabId of tabs.keys()) {
void chrome.debugger.detach({ tabId }).catch(() => {}) // ← unnecessary
}
tabs.clear()
}Fix: Don't detach debugger on relay loss. Keep debugger attached, mark relay as disconnected, reconnect WS, then re-announce existing sessions.
2. No WebSocket auto-reconnect
ws.onclose and ws.onerror only call onRelayClosed() — no reconnect attempt. The connection stays dead until the user manually clicks the toolbar icon.
Fix: Add exponential backoff reconnect in onRelayClosed():
function onRelayClosed(reason) {
relayWs = null
// DON'T detach debugger sessions
// Schedule reconnect
scheduleReconnect()
}
let reconnectAttempt = 0
function scheduleReconnect() {
const delay = Math.min(1000 * 2 ** reconnectAttempt, 30000) + Math.random() * 1000
reconnectAttempt++
setTimeout(async () => {
try {
await ensureRelayConnection()
reconnectAttempt = 0
// Re-announce all still-attached tabs
for (const [tabId, tab] of tabs.entries()) {
if (tab.state === 'connected') {
// Send attachedToTarget events for each tab
}
}
} catch {
scheduleReconnect()
}
}, delay)
}3. MV3 service worker state loss (lines ~19-24)
All tab/session state is in-memory Maps. When Chrome kills the MV3 service worker (~30s idle without activity), state is lost. The debugger may still be attached at the Chrome level, but the extension forgot about it.
Note: Since Chrome 118, active chrome.debugger sessions keep the worker alive, and since Chrome 116, WebSocket traffic resets the idle timer. But if both are briefly inactive, the worker can still die.
Fix: Persist minimal state (tabId, sessionId, targetId) to chrome.storage.session. On worker startup, rehydrate and validate with chrome.tabs.get().
4. No tab lifecycle cleanup (minor)
No chrome.tabs.onRemoved or chrome.tabs.onReplaced listeners. Closed/replaced tabs leave stale entries in the Maps, which can cause "No attached tab" errors.
Fix: Add listeners to clean up state when tabs close or get replaced (prerender swap).
Impact
This is the biggest friction point when using the Chrome relay. Every disconnect requires physical user intervention (clicking the toolbar button), which breaks automated workflows and makes the relay unreliable for anything beyond single-shot use.
Suggested Priority
The fixes are straightforward and contained within background.js. The most impactful single change is #1 (don't detach on WS drop) combined with #2 (auto-reconnect), which would eliminate most user-facing disconnects.