jackwener/OpenCLI · warning

[opencli] attach attempt ${attempt}/${MAX_ATTACH_RETRIES} fa

Error message

[opencli] attach attempt ${attempt}/${MAX_ATTACH_RETRIES} failed: ${lastError}, retrying in ${RETRY_DELAY_MS}ms...

What it means

ensureAttached retries chrome.debugger.attach up to MAX_ATTACH_RETRIES with RETRY_DELAY_MS between attempts (it also re-verifies the tab URL is debuggable before each retry). When an attempt fails with a transient error and more attempts remain, it logs this warning including the underlying chrome.debugger error and the retry delay. If all attempts fail, the final lastError is thrown to the caller.

Source

Thrown at extension/src/cdp.ts:168

  // this tab's armed network-capture state; detaching also disables the CDP
  // Network domain. Snapshot the capture so we can restore it after a successful
  // re-attach instead of silently dropping in-flight capture — otherwise any
  // non-navigate command that triggers a re-attach (a stale-attach health-check
  // failure during SPA navigation or third-party debugger interference) leaves
  // network-capture-read returning [] even though requests fired.
  const preservedNetworkCapture = networkCaptures.get(tabId);

  for (let attempt = 1; attempt <= MAX_ATTACH_RETRIES; attempt++) {
    try {
      // Force detach first to clear any stale state from other extensions
      try { await chrome.debugger.detach({ tabId }); } catch { /* ignore */ }
      await chrome.debugger.attach({ tabId }, '1.3');
      lastError = '';
      break; // Success
    } catch (e: unknown) {
      lastError = e instanceof Error ? e.message : String(e);
      if (attempt < MAX_ATTACH_RETRIES) {
        console.warn(`[opencli] attach attempt ${attempt}/${MAX_ATTACH_RETRIES} failed: ${lastError}, retrying in ${RETRY_DELAY_MS}ms...`);
        await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));
        // Re-verify tab URL before retrying (it may have changed)
        try {
          const tab = await chrome.tabs.get(tabId);
          if (!isDebuggableUrl(tab.url)) {
            lastError = `Tab URL changed to ${tab.url} during retry`;
            break; // Don't retry if URL became un-debuggable
          }
        } catch {
          // Tab is gone — don't fail early here.
          // Later retry layers can re-resolve a fresh automation tab/window.
          lastError = `Tab ${tabId} no longer exists`;
          // Don't break; fall through to retry
        }
      }
    }
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Close DevTools or any other chrome.debugger client attached to the target tab, then retry.
  2. Ensure the tab stays on an http/https URL (isDebuggableUrl) for the whole command.
  3. Wait for the automatic retry (RETRY_DELAY_MS); transient contention often clears on its own.
  4. If it persists across all retries, the final thrown lastError names the real cause — address that (e.g. detach other debuggers).

Example fix

// before: DevTools open on the tab while running: opencli browser eval ...
// after: detach DevTools (or close that window) and rerun the command
Defensive patterns

Strategy: retry

Validate before calling

const tab = await chrome.tabs.get(tabId);
if (!/^https?:/.test(tab.url ?? '')) {
  throw new Error(`Tab URL not debuggable: ${tab.url}`);
}

Type guard

function isDebuggable(url) {
  return typeof url === 'string' && /^https?:\/\//i.test(url);
}

Try / catch

try {
  await ensureAttached(tabId);
} catch (e) {
  if (/Another debugger|already attached/i.test(String(e.message))) {
    // close DevTools/other debugger clients, then retry once
  }
  throw e;
}

Prevention

When it happens

Trigger: chrome.debugger.attach({ tabId }, '1.3') throws — another debugger (DevTools) is already attached to the tab, another chrome.debugger client holds it, or the tab is transiently busy/navigating between retries; also when the tab URL changed to a non-debuggable URL (chrome://, Web Store) during retry.

Common situations: Developer has DevTools open on the tab while running an opencli command; two opencli clients attaching to the same tab; a redirect lands the tab on a chrome:// page mid-attach.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/2d4588b5b2ede6da. Report an issue: GitHub.