paperclipai/paperclip · error · RuntimeServicePortBindCollision

Runtime service could not bind allocated port ${port}

Error message

Runtime service could not bind allocated port ${port}

What it means

The service process is alive but has not bound its allocated port before the readiness timeout expired. The service is hanging or listening elsewhere, so the managed runtime service start is failed.

Source

Thrown at server/src/services/workspace-runtime.ts:4819

  throw new Error(`Readiness check failed for ${readinessUrl}: ${lastError}`);
}

async function waitForAllocatedPortBind(input: {
  service: Record<string, unknown>;
  port: number;
  child: ChildProcess;
}) {
  const deadline = Date.now() + resolveWorkspaceRuntimeReadinessTimeoutSec(input.service) * 1000;
  while (Date.now() < deadline) {
    if (input.child.exitCode !== null || input.child.signalCode !== null) {
      throw new Error("service process exited before binding its allocated port");
    }

    const ownerPid = await readLocalServicePortOwner(input.port);
    if (ownerPid) {
      const childPid = input.child.pid ?? null;
      if (!childPid || !(await isLocalServiceProcessOwnedBy(ownerPid, childPid))) {
        throw new RuntimeServicePortBindCollision(input.port);
      }
      // Require the same launched process group to retain ownership across a stability delay.
      // Cwd matching alone is insufficient because sibling services can share a workspace.
      await delay(250);
      if (input.child.exitCode !== null || input.child.signalCode !== null) {
        throw new Error("service process exited after losing its allocated port");
      }
      const stableOwnerPid = await readLocalServicePortOwner(input.port);
      if (!stableOwnerPid || !(await isLocalServiceProcessOwnedBy(stableOwnerPid, childPid))) {
        throw new RuntimeServicePortBindCollision(input.port);
      }
      return;
    }

    // A present listener proves only that some listener appeared. If listener ownership cannot
    // be attributed to this child after a stability delay, retry instead of accepting a sibling.
    // The presence read never binds the port, so it cannot steal the port from the child.
    if (await hasLoopbackPortListener(input.port)) {

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Make the runtime service listen on the allocated port, or configure a different free port.
  2. Check that nothing else grabbed the port between allocation and bind, then retry.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at server/src/services/workspace-runtime.ts:4666 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-18). Data as JSON: /api/errors/0c0de89477ef2e99. Report an issue: GitHub.