paperclipai/paperclip · error
Unable to reserve OpenCode port
Error message
Unable to reserve OpenCode port
What it means
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.
Source
Thrown at packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts:2393
/* server is still starting */
}
await new Promise((resolve) => setTimeout(resolve, 50));
}
const detail = redact(diagnostics());
throw new Error(
`provider_initialize_timeout: provider=opencode stage=health${detail ? ` stderrTail=${detail}` : ""}`,
);
}
async function reservePort(): Promise<number> {
const server = createServer();
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => resolve());
});
const address = server.address();
if (!address || typeof address === "string")
throw new Error("Unable to reserve OpenCode port");
const port = address.port;
await new Promise<void>((resolve, reject) =>
server.close((error) => (error ? reject(error) : resolve())),
);
return port;
}
async function* parseSseFrames(
stream: ReadableStream<Uint8Array>,
): AsyncIterable<{ raw: string; data: string }> {
const decoder = new TextDecoder();
let buffer = "";
for await (const chunk of stream as unknown as AsyncIterable<Uint8Array>) {
buffer += decoder.decode(chunk, { stream: true });
if (buffer.length > 1_048_576)
throw new Error("OpenCode SSE event exceeded the retained payload limit");
let boundary: RegExpExecArray | null;
while ((boundary = /\r?\n\r?\n/.exec(buffer)) !== null) {View on GitHub (pinned to 01ad858492)
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.
Example fix
// before
const address = server.address();
if (!address || typeof address === "string")
throw new Error("Unable to reserve OpenCode port");
// after
const address = server.address();
if (!address || typeof address === "string")
throw new Error("Unable to reserve OpenCode port");
// caller: retry reserveOpenCodePort() up to N times before failing startup Defensive patterns
Strategy: retry
Type guard
function isTcpAddress(a: unknown): a is import("node:net").AddressInfo {
return typeof a === "object" && a !== null && typeof (a as any).port === "number";
} Try / catch
try {
port = await reserveOpenCodePort();
} catch (e) {
if (e instanceof Error && e.message === "Unable to reserve OpenCode port") {
port = await reserveOpenCodePort(); // single retry; persistent failure = environment issue
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- No Tailscale address was detected during setup. The saved co
- No Tailscale address was detected during setup. The saved co
- Anthropic Managed Agents request failed with HTTP ${response
- ${label} has existing tables but no migration journal. Run m
- failed company transfer runs stranded in applying by a resta
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/f7f31c461df84c0b.
Report an issue: GitHub.