{"record":{"id":"084574de46909751","repo":"jackwener/OpenCLI","slug":"app-launched-but-cdp-not-available-on-port-port","errorCode":null,"errorMessage":"App launched but CDP not available on port ${port} after ${POLL_TIMEOUT_MS / 1000}s","messagePattern":"App launched but CDP not available on port (.+?) after (.+?)s","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"src/launcher.ts","lineNumber":347,"sourceCode":"export function electronLaunchArgs(port: number, extraArgs: string[] = []): string[] {\n  return [\n    `--remote-debugging-port=${port}`,\n    '--remote-allow-origins=*',\n    ...extraArgs,\n  ];\n}\n\nfunction manualElectronLaunchHint(label: string, port: number): string {\n  return `Start ${label} manually with --remote-debugging-port=${port} --remote-allow-origins=*, then either:`;\n}\n\nasync function pollForReady(port: number): Promise<void> {\n  const deadline = Date.now() + POLL_TIMEOUT_MS;\n  while (Date.now() < deadline) {\n    if (await probeCDP(port, 1_000)) return;\n    await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));\n  }\n  throw new CommandExecutionError(\n    `App launched but CDP not available on port ${port} after ${POLL_TIMEOUT_MS / 1000}s`,\n    'The app may be slow to start. Try running the command again.',\n  );\n}\n\n/**\n * Main entry point: resolve an Electron app to a CDP endpoint URL.\n *\n * Returns the endpoint URL: http://127.0.0.1:{port}\n */\nexport async function resolveElectronEndpoint(site: string): Promise<string> {\n  const app = getElectronApp(site);\n  if (!app) {\n    throw new CommandExecutionError(\n      `No Electron app registered for site \"${site}\"`,\n      'Register the app in ~/.opencli/apps.yaml or check the site name.',\n    );\n  }","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/launcher.ts#L329-L365","documentation":"After launching the Electron app, pollForReady probes the Chrome DevTools Protocol port (probeCDP) every POLL_INTERVAL_MS until POLL_TIMEOUT_MS elapses. If CDP never answers within that window, it assumes the debug port never opened and throws this CommandExecutionError.","triggerScenarios":"resolveElectronEndpoint launches the app with --remote-debugging-port=<port>, the process starts, but probeCDP(port) keeps failing until the timeout expires (e.g. app ignores the debug flag, port blocked, or app takes longer than POLL_TIMEOUT_MS to open the listener).","commonSituations":"Slow machine or heavy app startup exceeding the timeout; app was already running without the debug flag so the new instance defers to it; firewall/security software blocking localhost connections; a wrapper or custom binary that drops the --remote-debugging-port argument.","solutions":["Retry the command — a slow-starting app may simply need more time.","Quit any already-running instance of the app first so the launched instance honors the debug port.","Verify the app is launched with --remote-debugging-port (check the custom binary/wrapper in apps.yaml doesn't strip arguments).","Check that nothing (firewall, VPN, security software) blocks connections to localhost:<port>."],"exampleFix":"// before: app already running without debug port\n$ myapp-cli open   # times out: CDP not available\n// after\n$ pkill -f MyApp && myapp-cli open","handlingStrategy":"retry","validationCode":"const isOpen = await probeCDP(port, 1000).catch(() => false);\nif (!isOpen) console.warn(`CDP port ${port} not open before launch; ensure no stale app instance is running`);","typeGuard":"function isCdpReachable(port: number): boolean {\n  return fetch(`http://127.0.0.1:${port}/json/version`)\n    .then((r) => r.ok)\n    .catch(() => false) as unknown as boolean;\n}","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try {\n    const endpoint = await resolveElectronEndpoint(port);\n    break;\n  } catch (e) {\n    if (e instanceof CommandExecutionError && /CDP not available/.test(e.message) && attempt < 2) {\n      await new Promise((r) => setTimeout(r, 2000));\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["Quit existing app instances before launching so the debug port binds.","Launch on a free port and pass --remote-debugging-port explicitly.","Increase the timeout / check app startup time on slow machines.","Confirm firewalls allow localhost connections to the chosen port."],"tags":["electron","cdp","timeout","devtools"],"backgroundTag":"cdp-port-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}