{"record":{"id":"f6863f2695d08c17","repo":"paperclipai/paperclip","slug":"sandbox-callback-bridge-did-not-report-a-listening","errorCode":null,"errorMessage":"Sandbox callback bridge did not report a listening port.","messagePattern":"Sandbox callback bridge did not report a listening port\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/adapter-utils/src/sandbox-callback-bridge.ts","lineNumber":1113,"sourceCode":"    shellCommand,\n  );\n  requireSuccessfulResult(\"wait for sandbox callback bridge readiness\", readyResult);\n\n  let readyData: { host?: string; port?: number; baseUrl?: string; pid?: number };\n  try {\n    readyData = JSON.parse(readyResult.stdout.trim()) as { host?: string; port?: number; baseUrl?: string; pid?: number };\n  } catch (error) {\n    throw new Error(\n      `Sandbox callback bridge wrote invalid readiness JSON: ${error instanceof Error ? error.message : String(error)}`,\n    );\n  }\n\n  const host = typeof readyData.host === \"string\" && readyData.host.trim().length > 0\n    ? readyData.host.trim()\n    : \"127.0.0.1\";\n  const port = typeof readyData.port === \"number\" && Number.isFinite(readyData.port) ? readyData.port : 0;\n  if (!port) {\n    throw new Error(\"Sandbox callback bridge did not report a listening port.\");\n  }\n  const baseUrl =\n    typeof readyData.baseUrl === \"string\" && readyData.baseUrl.trim().length > 0\n      ? readyData.baseUrl.trim()\n      : `http://${host}:${port}`;\n\n  return {\n    baseUrl,\n    host,\n    port,\n    pid: typeof readyData.pid === \"number\" && Number.isFinite(readyData.pid) ? readyData.pid : 0,\n    directories,\n    stop: async () => {\n      const stopResult = await input.runner.execute({\n        command: shellCommand,\n        args: shellCommandArgs(\n          [\n            `if [ -s ${shellQuote(directories.pidFile)} ]; then`,","sourceCodeStart":1095,"sourceCodeEnd":1131,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapter-utils/src/sandbox-callback-bridge.ts#L1095-L1131","documentation":"Thrown when the parsed readiness JSON exists but its `port` field is missing, zero, or non-finite. The bridge server is expected to bind a TCP port and report it; a port of 0/NaN means the server either failed to listen (e.g. port 0 ephemeral was requested but the write of the real port never happened) or wrote a non-numeric port. This is a fail-closed guard so the orchestrator never returns a baseUrl pointing at port 0.","triggerScenarios":"startSandboxCallbackBridge parsed readyData successfully but readyData.port is undefined, 0, Infinity, -1, or a string coerced away. Occurs when the remote bridge binds but its ready.json write omits `port`, or writes port 0 because process.env.PAPERCLIP_BRIDGE_PORT defaulted and the actual bound port was not written back.","commonSituations":"Bridge server code path changed and stopped emitting port; the `server.listen(0)` callback that writes ready.json was replaced; a port string vs number type regression in the bridge source generator; bridge process started but crashed after listening, before writing port.","solutions":["Read the generated bridge server source (getSandboxCallbackBridgeServerSource) and confirm it writes the real bound port into ready.json after `server.listen`.","Check directories.logFile on the remote host for a bridge runtime error after the listen call.","Confirm PAPERCLIP_BRIDGE_PORT was not forced to a non-listenable value and that the bridge host can bind.","Log readyData verbatim before the port check to see which field is malformed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const readyData = JSON.parse(raw) as { port?: unknown };\nif (typeof readyData.port !== 'number' || !Number.isFinite(readyData.port) || readyData.port <= 0) {\n  throw new Error(`Bridge did not bind a port; readyData=${JSON.stringify(readyData)}`);\n}","typeGuard":"function hasValidPort(v: unknown): v is { port: number } {\n  return typeof (v as { port?: unknown })?.port === 'number'\n    && Number.isFinite((v as { port: number }).port)\n    && (v as { port: number }).port > 0;\n}","tryCatchPattern":null,"preventionTips":["Pin the generated bridge server source so the listen callback always writes the real bound port.","Integration-test the bridge against an ephemeral port and assert a positive port is reported.","Watch for regressions in getSandboxCallbackBridgeServerSource that drop the port field."],"tags":["sandbox","bridge","port","startup","validation"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}