{"record":{"id":"c9b7ceb0fbb12842","repo":"paperclipai/paperclip","slug":"non-numeric-tcp-port-portkey","errorCode":null,"errorMessage":"non-numeric TCP port: ${portKey}","messagePattern":"non-numeric TCP port: (.+?)","errorType":"validation","errorClass":"ServeParseError","httpStatus":null,"severity":"error","filePath":"packages/tailscale-https-broker/src/serve-config.ts","lineNumber":70,"sourceCode":"\n/**\n * Parse serve status JSON into a normalized, port-keyed model. Tolerates extra\n * top-level fields (Tailscale evolves its schema) but strictly validates the\n * `TCP` and `Web` shapes it depends on.\n */\nexport function parseServeStatus(json: unknown): ParsedServe {\n  if (!isObject(json)) {\n    throw new ServeParseError(\"serve status must be a JSON object\");\n  }\n  const entries = new Map<number, ServeEntry>();\n\n  const tcp = json.TCP;\n  const httpsPorts = new Set<number>();\n  if (tcp !== undefined && tcp !== null) {\n    if (!isObject(tcp)) throw new ServeParseError(\"TCP must be an object\");\n    for (const [portKey, value] of Object.entries(tcp)) {\n      if (!/^[0-9]+$/.test(portKey)) {\n        throw new ServeParseError(`non-numeric TCP port: ${portKey}`);\n      }\n      const port = assertCanonicalPort(Number(portKey));\n      if (!isObject(value)) throw new ServeParseError(`TCP[${portKey}] must be an object`);\n      if (value.HTTPS === true) httpsPorts.add(port);\n      if (!entries.has(port)) entries.set(port, { port, https: value.HTTPS === true, handlers: [] });\n      else entries.get(port)!.https = value.HTTPS === true;\n    }\n  }\n\n  const web = json.Web;\n  if (web !== undefined && web !== null) {\n    if (!isObject(web)) throw new ServeParseError(\"Web must be an object\");\n    for (const [hostKey, value] of Object.entries(web)) {\n      const port = portFromWebKey(hostKey);\n      if (!isObject(value)) throw new ServeParseError(`Web[${hostKey}] must be an object`);\n      const handlersRaw = value.Handlers;\n      const handlers: ServeHandler[] = [];\n      if (handlersRaw !== undefined && handlersRaw !== null) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/tailscale-https-broker/src/serve-config.ts#L52-L88","documentation":"Port-key guard in parseServeStatus: a key inside the TCP object of serve status is not numeric, so it cannot be mapped to a port number for the port-keyed model. The TCP block's keys are expected to be port strings.","triggerScenarios":"Thrown at packages/tailscale-https-broker/src/serve-config.ts:70 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Correct the TCP section key so it is a numeric port."],"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-14T00:17:10.932Z"}