{"record":{"id":"119051881f1888e3","repo":"paperclipai/paperclip","slug":"cloud-runtime-identity-has-an-invalid-label","errorCode":null,"errorMessage":"Cloud runtime identity has an invalid ${label}","messagePattern":"Cloud runtime identity has an invalid (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/cloud-runtime-identity.ts","lineNumber":221,"sourceCode":"  if (env === process.env && currentIdentity) return currentIdentity.canonicalOrigin;\n  const candidate = nonEmpty(env.PAPERCLIP_PUBLIC_URL)\n    ?? nonEmpty(env.PAPERCLIP_AUTH_PUBLIC_BASE_URL)\n    ?? nonEmpty(env.PAPERCLIP_API_URL);\n  if (!candidate) return null;\n  try {\n    return new URL(candidate).origin;\n  } catch {\n    return null;\n  }\n}\n\n/** The asserted Cloud origin only. Callers retain their non-Cloud precedence. */\nexport function runtimeCanonicalOrigin(): string | null {\n  return currentIdentity?.canonicalOrigin ?? null;\n}\n\nfunction decodeJsonPart(part: string, label: string): Record<string, unknown> {\n  if (!/^[A-Za-z0-9_-]+$/.test(part)) throw new Error(`Cloud runtime identity has an invalid ${label}`);\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(Buffer.from(part, \"base64url\").toString(\"utf8\"));\n  } catch {\n    throw new Error(`Cloud runtime identity has an invalid ${label}`);\n  }\n  if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n    throw new Error(`Cloud runtime identity has an invalid ${label}`);\n  }\n  return parsed as Record<string, unknown>;\n}\n\nfunction publicKeyForKid(env: NodeJS.ProcessEnv, kid: string) {\n  const raw = nonEmpty(env.PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS);\n  if (!raw) throw new Error(\"PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS is not configured\");\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/cloud-runtime-identity.ts#L203-L239","documentation":"decodeJsonPart decodes one base64url-delimited part of the Cloud runtime identity compact JWS (protected header or payload). It throws this error when the part contains characters outside [A-Za-z0-9_-] (i.e. is not valid base64url), when base64url decoding plus JSON.parse fails, or — as here at line 221 — before decoding, when the pre-parse charset check fails. The label in the message is 'protected header' or 'payload' depending on the caller.","triggerScenarios":"verifyCloudRuntimeIdentityAssertion (via verifyClaims) is given a compactJws whose header or payload segment contains invalid base64url characters (e.g. '+' or '/' or '='), is not valid base64url encoding, or decodes to bytes that are not valid JSON.","commonSituations":"A caller passes a standard base64 JWT (with '+', '/', '=') instead of the base64url form; the assertion string was truncated or corrupted in transit, storage, or a shell command (quoting/line-wrap damage); someone pasted a URL-encoded or padded token; a test fixture was hand-crafted with a malformed segment.","solutions":["Regenerate or re-fetch the runtime identity assertion from the Paperclip Cloud control plane instead of reusing a stored copy; use the token exactly as issued.","Check that the string was not damaged in transit: shell-quote it, avoid line wrapping in YAML/env files, and confirm no truncation when copying.","If you must construct the JWS yourself, base64url-encode (RFC 4648 §5, no padding) the JSON header and payload.","Log/inspect the failing part and confirm it matches ^[A-Za-z0-9_-]+$ and JSON-decodes after base64url decoding before calling the API."],"exampleFix":"// before (standard base64 with padding)\nconst part = Buffer.from(json).toString(\"base64\"); // e.g. \"eyJ...+g==\"\n// after (base64url, no padding)\nconst part = Buffer.from(json).toString(\"base64url\");","handlingStrategy":"validation","validationCode":"function isBase64UrlPart(part: string): boolean {\n  return /^[A-Za-z0-9_-]+$/.test(part) &&\n    (() => { try { JSON.parse(Buffer.from(part, \"base64url\").toString(\"utf8\")); return true; } catch { return false; } })();\n}\n// before sending the assertion to the API:\nconst [h, p, s] = compactJws.split(\".\");\nif (!h || !p || !s || !isBase64UrlPart(h) || !isBase64UrlPart(p)) {\n  throw new Error(\"assertion is not a well-formed base64url compact JWS\");\n}","typeGuard":"function isWellFormedJws(token: string): boolean {\n  const parts = token.split(\".\");\n  if (parts.length !== 3 || parts.some((p) => !p)) return false;\n  return parts.every((p) => /^[A-Za-z0-9_-]+$/.test(p));\n}","tryCatchPattern":"try {\n  verifyCloudRuntimeIdentityAssertion({ compactJws, expectedPreviousOrigin });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"invalid protected header\")) {\n    // token damaged or wrongly encoded — re-fetch a fresh assertion from the control plane\n  }\n  throw err;\n}","preventionTips":["Never re-encode a base64url token to standard base64 (no '+', '/', or '=')","Quote the token in shell/YAML/env files to prevent mangling and line wrapping","Copy tokens verbatim from the Cloud control plane; avoid truncation in logs or ticket text","Round-trip decode the header/payload locally before submitting"],"tags":["jwt","base64url","encoding","validation"],"backgroundTag":"invalid-json-response","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}