paperclipai/paperclip · error · RuntimeServicePortBindCollision

Runtime service could not bind allocated port ${port} (${dia

Error message

Runtime service could not bind allocated port ${port} (${diagnosis})

What it means

The runtime service reported EADDRINUSE-class bind failure on its allocated port, diagnosed as a bind collision; startLocalRuntimeService re-runs allocation skipping quarantined port pairs, and the collision is thrown as a retryable error.

Source

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

    if (bindCollision && port) throw new RuntimeServicePortBindCollision(port);
    if (exposureHostCollision && port) {
      // A verified host listener holds the assigned exposure port. Quarantine the
      // pair so the bounded re-allocation never re-offers it, then throw a retryable
      // collision. `startLocalRuntimeService` re-runs allocation, which skips the
      // quarantined pair and takes the next free pair inside the dedicated range.
      // This hardens a real host that races an external process for a range port.
      for (const collisionPort of exposureCollisionPorts) {
        quarantinedRuntimeExposurePorts.add(collisionPort);
      }
      if (input.onLog) {
        await input.onLog(
          "stderr",
          `[service:${serviceName}] exposure port ${port} collided during startup (EADDRINUSE); `
            + `${exposureCollisionDiagnosis ?? "owner unavailable"}. `
            + `Quarantined pair ${exposureCollisionPorts.join("/")} and reallocating.\n`,
        ).catch(() => undefined);
      }
      throw new RuntimeServicePortBindCollision(port, exposureCollisionDiagnosis, true);
    }
    const deploymentBindConflict = /local_trusted requires server\.bind=loopback/i.test(
      `${failureMessage}\n${serviceOutputExcerpt}`,
    );
    // The guest reported an assigned-port EADDRINUSE, but no host listener owned
    // the port. Explain that the runtime did not quarantine the pair, so a future
    // occurrence needs no diagnostic cycle and the pool stays intact.
    const unverifiedExposureCollision = exposureTextNamesAssignedPort && !exposureHostCollision;
    const actionableFailure = deploymentBindConflict
      ? `${failureMessage} | deployment/bind conflict: local_trusted requires server.bind=loopback; the managed runtime requested an incompatible bind mode`
      : unverifiedExposureCollision
        ? `${failureMessage} | exposure port collision not verified: the guest reported EADDRINUSE on assigned port ${exposureNamedPorts.join("/")}, but no host listener owns it (${exposureCollisionDiagnosis ?? "owner unavailable"}); the runtime did not quarantine the pair`
        : failureMessage;
    throw new Error(
      `Failed to start runtime service "${serviceName}": ${actionableFailure}${serviceOutputExcerpt ? ` | output: ${serviceOutputExcerpt.trim()}` : ""}`,
    );
  });

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Let the bounded re-allocation retry pick the next free port pair
  2. Free the collided port or stop the external process holding it
  3. Check the quarantine list is not exhausted for the dedicated port range
  4. Inspect the bind diagnosis in the error for owner information
Defensive patterns

Strategy: retry

When it happens

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

Common situations: See trigger scenarios.


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