jackwener/OpenCLI · error · CommandFailure
bound_tab_not_debuggable
bound_tab_not_debuggable
Error message
Bound tab for session "${session.session}" is not debuggable (${preferredTab.url ?? 'unknown URL'}). What it means
When a bound session has a preferredTabId, resolveTab fetches that preferred tab directly; if it exists but its URL is not debuggable (not http(s)/about:blank/data:), the library throws because CDP cannot attach to browser-internal pages. This is the preferred-tab branch of the same check as error 5210.
Source
Thrown at extension/src/background.ts:1537
automationSessions.delete(leaseKey);
throw new CommandFailure(
'bound_tab_gone',
`Bound tab for session "${existingSession.session}" no longer exists.`,
'Run "opencli browser bind" again, then retry the command.',
);
}
console.warn(`[opencli] Tab ${tabId} no longer exists, re-resolving`);
}
}
const existingPreferredTabId = existingSession?.preferredTabId ?? null;
if (existingSession && existingPreferredTabId !== null) {
const session = existingSession;
try {
const preferredTab = await chrome.tabs.get(existingPreferredTabId);
if (isDebuggableUrl(preferredTab.url)) return { tabId: preferredTab.id!, tab: preferredTab };
if (!session.owned) {
throw new CommandFailure(
'bound_tab_not_debuggable',
`Bound tab for session "${session.session}" is not debuggable (${preferredTab.url ?? 'unknown URL'}).`,
'Switch the tab to an http(s) page or run "opencli browser bind" on another tab.',
);
}
} catch (err) {
if (err instanceof CommandFailure) throw err;
await removeLeaseSession(leaseKey);
if (!session.owned) {
throw new CommandFailure(
'bound_tab_gone',
`Bound tab for session "${session.session}" no longer exists.`,
'Run "opencli browser bind" again, then retry the command.',
);
}
return createOwnedTabLease(leaseKey, initialUrl);
}
}View on GitHub (pinned to 49907e53dc)
Solutions
- Switch the bound tab to an http(s) page as the remediation hint says
- Re-run 'opencli browser bind' on another tab that shows web content
- Navigate programmatically: opencli browser navigate https://…
- Keep the bound tab pinned to real web pages during automation
Example fix
// before preferredTab.url = 'chrome://newtab' → bound_tab_not_debuggable // after opencli browser navigate https://example.com // then retry
Defensive patterns
Strategy: validation
Validate before calling
const preferred = await chrome.tabs.get(preferredTabId);
if (!/^https?:/i.test(preferred.url ?? '')) {
await chrome.tabs.update(preferredTabId, { url: 'https://example.com' });
} Type guard
function isWebUrl(url?: string): boolean {
return !!url && (url.startsWith('http://') || url.startsWith('https://'));
} Try / catch
try {
await cmd();
} catch (e) {
if ((e as Error).message.includes('not debuggable')) {
await chrome.tabs.update(tabId, { url: START_URL });
await retry(cmd);
} else throw e;
} Prevention
- Avoid typing chrome:// URLs into the automation tab
- Navigate programmatically back to http(s) before commands
- Monitor tab URL changes with chrome.tabs.onUpdated and re-bind when the URL becomes non-web
- Use a dedicated profile/window for automation
When it happens
Trigger: existingSession.preferredTabId !== null, chrome.tabs.get succeeds, but preferredTab.url fails isDebuggableUrl (chrome://, edge://, extension page, file://) and the session is unowned.
Common situations: The tab bound via 'opencli browser bind' was navigated to chrome://version, a Chrome Web Store page, or an internal new-tab page before running the next command.
Related errors
- Bound tab for session "${session.session}" is not debuggable
- Cannot debug tab ${tabId}: URL is ${tab.url ?? 'unknown'}
- bound_tab_gone
- Tab ${tabId} no longer exists
- attach failed: ${lastError}${hint}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3304c0d134c4a6b2.
Report an issue: GitHub.