{"record":{"id":"8dcc062d688498ca","repo":"paperclipai/paperclip","slug":"invalid-port","errorCode":"invalid_port","errorMessage":"an app listener in the dedicated app range is required","messagePattern":"an app listener in the dedicated app range is required","errorType":"error_code","errorClass":"ProtocolError","httpStatus":null,"severity":"error","filePath":"packages/tailscale-https-broker/src/protocol.ts","lineNumber":162,"sourceCode":"    try {\n      port = assertCanonicalPort(listener.port);\n    } catch (error) {\n      throw new ProtocolError(\"invalid_port\", (error as Error).message, requestId);\n    }\n    return { purpose: purpose as OwnedListener[\"purpose\"], port };\n  });\n\n  // Reject duplicate ports / duplicate purposes within one request.\n  const ports = new Set(listeners.map((l) => l.port));\n  const purposes = new Set(listeners.map((l) => l.purpose));\n  if (ports.size !== listeners.length || purposes.size !== listeners.length) {\n    throw new ProtocolError(\"malformed_request\", \"duplicate listener port or purpose\", requestId);\n  }\n\n  const app = listeners.find((listener) => listener.purpose === \"app\");\n  const hmr = listeners.find((listener) => listener.purpose === \"vite_hmr\");\n  if (!app || app.port < DEFAULT_APP_PORT_MIN || app.port > DEFAULT_APP_PORT_MAX) {\n    throw new ProtocolError(\"invalid_port\", \"an app listener in the dedicated app range is required\", requestId);\n  }\n  if (hmr && hmr.port !== app.port + DEFAULT_HMR_PORT_OFFSET) {\n    throw new ProtocolError(\"invalid_port\", \"vite_hmr must be the app port companion\", requestId);\n  }\n\n  return { op: \"reserve\", requestId, runtimeId, listeners };\n}\n\nfunction assertExactKeys(\n  obj: Record<string, unknown>,\n  allowed: string[],\n  requestId: string | null,\n): void {\n  const allowedSet = new Set(allowed);\n  for (const key of Object.keys(obj)) {\n    if (!allowedSet.has(key)) {\n      throw new ProtocolError(\"malformed_request\", `unknown field: ${key}`, requestId);\n    }","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/tailscale-https-broker/src/protocol.ts#L144-L180","documentation":"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.","triggerScenarios":"Thrown at packages/tailscale-https-broker/src/protocol.ts:162 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Configure at least one app listener within the dedicated app port range before issuing this request."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}