paperclipai/paperclip · error · ProtocolError

invalid_port

invalid_port

Error message

an app listener in the dedicated app range is required

What it means

Semantic listener check in decodeRequest for expose requests: the runtime declared only non-app listeners, but at least one listener with an app purpose inside the dedicated app port range is required. ProtocolError('invalid_port') surfaces the policy violation after each port passed assertCanonicalPort.

Source

Thrown at packages/tailscale-https-broker/src/protocol.ts:162

    try {
      port = assertCanonicalPort(listener.port);
    } catch (error) {
      throw new ProtocolError("invalid_port", (error as Error).message, requestId);
    }
    return { purpose: purpose as OwnedListener["purpose"], port };
  });

  // Reject duplicate ports / duplicate purposes within one request.
  const ports = new Set(listeners.map((l) => l.port));
  const purposes = new Set(listeners.map((l) => l.purpose));
  if (ports.size !== listeners.length || purposes.size !== listeners.length) {
    throw new ProtocolError("malformed_request", "duplicate listener port or purpose", requestId);
  }

  const app = listeners.find((listener) => listener.purpose === "app");
  const hmr = listeners.find((listener) => listener.purpose === "vite_hmr");
  if (!app || app.port < DEFAULT_APP_PORT_MIN || app.port > DEFAULT_APP_PORT_MAX) {
    throw new ProtocolError("invalid_port", "an app listener in the dedicated app range is required", requestId);
  }
  if (hmr && hmr.port !== app.port + DEFAULT_HMR_PORT_OFFSET) {
    throw new ProtocolError("invalid_port", "vite_hmr must be the app port companion", requestId);
  }

  return { op: "reserve", requestId, runtimeId, listeners };
}

function assertExactKeys(
  obj: Record<string, unknown>,
  allowed: string[],
  requestId: string | null,
): void {
  const allowedSet = new Set(allowed);
  for (const key of Object.keys(obj)) {
    if (!allowedSet.has(key)) {
      throw new ProtocolError("malformed_request", `unknown field: ${key}`, requestId);
    }

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Configure at least one app listener within the dedicated app port range before issuing this request.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/tailscale-https-broker/src/protocol.ts:162 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/8dcc062d688498ca. Report an issue: GitHub.