{"record":{"id":"f7f31c461df84c0b","repo":"paperclipai/paperclip","slug":"unable-to-reserve-opencode-port","errorCode":null,"errorMessage":"Unable to reserve OpenCode port","messagePattern":"Unable to reserve OpenCode port","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts","lineNumber":2393,"sourceCode":"      /* server is still starting */\n    }\n    await new Promise((resolve) => setTimeout(resolve, 50));\n  }\n  const detail = redact(diagnostics());\n  throw new Error(\n    `provider_initialize_timeout: provider=opencode stage=health${detail ? ` stderrTail=${detail}` : \"\"}`,\n  );\n}\n\nasync function reservePort(): Promise<number> {\n  const server = createServer();\n  await new Promise<void>((resolve, reject) => {\n    server.once(\"error\", reject);\n    server.listen(0, \"127.0.0.1\", () => resolve());\n  });\n  const address = server.address();\n  if (!address || typeof address === \"string\")\n    throw new Error(\"Unable to reserve OpenCode port\");\n  const port = address.port;\n  await new Promise<void>((resolve, reject) =>\n    server.close((error) => (error ? reject(error) : resolve())),\n  );\n  return port;\n}\n\nasync function* parseSseFrames(\n  stream: ReadableStream<Uint8Array>,\n): AsyncIterable<{ raw: string; data: string }> {\n  const decoder = new TextDecoder();\n  let buffer = \"\";\n  for await (const chunk of stream as unknown as AsyncIterable<Uint8Array>) {\n    buffer += decoder.decode(chunk, { stream: true });\n    if (buffer.length > 1_048_576)\n      throw new Error(\"OpenCode SSE event exceeded the retained payload limit\");\n    let boundary: RegExpExecArray | null;\n    while ((boundary = /\\r?\\n\\r?\\n/.exec(buffer)) !== null) {","sourceCodeStart":2375,"sourceCodeEnd":2411,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts#L2375-L2411","documentation":"Thrown when reserving an ephemeral TCP port for the OpenCode server fails the invariant check: server.address() is null or returns a string (e.g. a Unix socket path / pipe name) instead of an AddressInfo with a numeric port. The port reservation is the first step of spawning the server, so startup aborts.","triggerScenarios":"net server listening on port 0 at 127.0.0.1 but address() returns null (server closed already) or a string (bound to a pipe/socket rather than TCP), which should not happen under normal conditions — indicates an environment or runtime anomaly.","commonSituations":"Hostile or misconfigured environment where IPv6-only/pipe binding changes address(); monkey-patched or restricted net module; extremely port-constrained environments causing listen errors surfaced differently.","solutions":["Retry port reservation — a single failed attempt is usually transient.","Verify the Node runtime's net module behaves normally (no patches, no restricted sandbox) and that 127.0.0.1 TCP binding is allowed.","Check server 'error' events on the listener that might race with the resolve, leaving address() null.","As a fallback, let the OS choose by listening on port 0 and re-reading address() after listen confirms, with explicit AddressInfo type narrowing."],"exampleFix":"// before\nconst address = server.address();\nif (!address || typeof address === \"string\")\n  throw new Error(\"Unable to reserve OpenCode port\");\n\n// after\nconst address = server.address();\nif (!address || typeof address === \"string\")\n  throw new Error(\"Unable to reserve OpenCode port\");\n// caller: retry reserveOpenCodePort() up to N times before failing startup","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isTcpAddress(a: unknown): a is import(\"node:net\").AddressInfo {\n  return typeof a === \"object\" && a !== null && typeof (a as any).port === \"number\";\n}","tryCatchPattern":"try {\n  port = await reserveOpenCodePort();\n} catch (e) {\n  if (e instanceof Error && e.message === \"Unable to reserve OpenCode port\") {\n    port = await reserveOpenCodePort(); // single retry; persistent failure = environment issue\n  } else throw e;\n}","preventionTips":["Retry ephemeral port reservation once before failing startup","Avoid sandbox/patched environments that alter net server address() behavior","Ensure TCP binding to 127.0.0.1 is permitted in the host environment"],"tags":["network","port","startup","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}