{"record":{"id":"7d8cf74a31e86deb","repo":"paperclipai/paperclip","slug":"port-must-be-a-json-number","errorCode":null,"errorMessage":"port must be a JSON number","messagePattern":"port must be a JSON number","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailscale-https-broker/src/integers.ts","lineNumber":18,"sourceCode":"/**\n * Canonical integer parsing for the broker. Commands and Serve mutations are\n * generated only from integers that pass these checks, never from raw strings,\n * URLs, or unvalidated JSON (PAP-17050 verdict requirement #4).\n */\n\n/** Ports are constrained to the valid TCP range. */\nexport const MIN_PORT = 1;\nexport const MAX_PORT = 65535;\n\n/**\n * Assert a JSON-decoded value is a canonical, safe, in-range port number.\n * Rejects non-numbers, non-integers, NaN/Infinity, negatives, and out-of-range\n * values. Returns the number so call sites read as validated.\n */\nexport function assertCanonicalPort(value: unknown): number {\n  if (typeof value !== \"number\") {\n    throw new Error(\"port must be a JSON number\");\n  }\n  if (!Number.isInteger(value)) {\n    throw new Error(\"port must be an integer\");\n  }\n  if (value < MIN_PORT || value > MAX_PORT) {\n    throw new Error(`port out of range [${MIN_PORT}, ${MAX_PORT}]`);\n  }\n  return value;\n}\n\n/**\n * Parse an integer from an untrusted STRING with strict canonical rules.\n * Rejects: empty, whitespace, signs, leading zeros (non-canonical), decimals,\n * exponents, thousands separators, Unicode digits, and anything that does not\n * round-trip exactly back to its canonical decimal form. Used at any boundary\n * where a numeric value could arrive as text.\n */\nexport function parseCanonicalIntegerString(raw: unknown): number {","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/tailscale-https-broker/src/integers.ts#L1-L36","documentation":"assertCanonicalPort guard: the JSON-decoded port value is not a JS number at all (string, null, object, etc.). Ports are never derived from raw strings or unvalidated JSON, so the value is rejected before any command or Serve mutation is generated from it.","triggerScenarios":"Thrown at packages/tailscale-https-broker/src/integers.ts:18 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Provide the port as a JSON number, not a string or other type."],"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"}