{"record":{"id":"fc4c6326e2e86ab4","repo":"Hmbown/CodeWhale","slug":"key-id-must-match-key-id-re","errorCode":null,"errorMessage":"key_id must match ${KEY_ID_RE}","messagePattern":"key_id must match (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/scripts/facts-publish.mjs","lineNumber":296,"sourceCode":"    channel,\n    facts_version: factsVersion,\n    published_at: publishedAt,\n    applies_to: typeof source.applies_to === \"string\" ? source.applies_to.trim() : \"*\",\n    models: source.models ?? [],\n    provider_defaults: source.provider_defaults ?? {},\n    release: source.release ?? null,\n    announcements: source.announcements ?? [],\n  };\n  if (source.not_after) payload.not_after = source.not_after;\n  const payloadErrors = validateSource(payload);\n  if (payloadErrors.length || utcTime(publishedAt) === null || !Number.isSafeInteger(factsVersion) || factsVersion <= 0 || !CHANNEL_RE.test(channel)) {\n    throw new Error(\"invalid signed payload metadata\");\n  }\n  return payload;\n}\n\nexport function buildEnvelope({ privateKey, keyId, payload }) {\n  if (!KEY_ID_RE.test(keyId)) throw new Error(`key_id must match ${KEY_ID_RE}`);\n  const payloadBytes = Buffer.from(canonicalize(payload), \"utf8\");\n  if (payloadBytes.length > MAX_PAYLOAD_BYTES) throw new Error(`payload exceeds ${MAX_PAYLOAD_BYTES} bytes`);\n  const sig = signPayload(privateKey, keyId, payloadBytes);\n  const sha256 = createHash(\"sha256\").update(payloadBytes).digest(\"hex\");\n  const envelope = {\n    envelope: ENVELOPE_VERSION,\n    channel: payload.channel,\n    facts_version: payload.facts_version,\n    schema_version: payload.schema_version,\n    key_id: keyId,\n    alg: \"ed25519\",\n    applies_to: payload.applies_to,\n    published_at: payload.published_at,\n    payload_b64: payloadBytes.toString(\"base64\"),\n    sig_b64: sig.toString(\"base64\"),\n    sigs: [],\n    sha256,\n  };","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/web/scripts/facts-publish.mjs#L278-L314","documentation":"buildEnvelope signs a facts payload and wraps it in a signed envelope. Before doing any work it validates the keyId against the repository's KEY_ID_RE regular expression and throws this error when the identifier does not conform to the pinned key-id syntax. Key ids must be canonical so verifiers can match them against pinned trusted keys.","triggerScenarios":"Calling buildEnvelope({ privateKey, keyId, payload }) with a keyId that fails KEY_ID_RE.test(keyId) — e.g. empty string, contains illegal characters, wrong case, or extra whitespace.","commonSituations":"Passing a human-friendly key label ('my key') or a path-like id instead of the canonical id used when the key was pinned; copy-pasting a key id with trailing newline or spaces; upgrading the KEY_ID_RE pattern so previously-valid ids no longer match.","solutions":["Print the keyId and match it against KEY_ID_RE (imported from this module) to see which character violates it","Trim whitespace/newlines from the keyId before passing it","Use the exact key id recorded in the trusted-keys pin list (validateTrustedKeys accepts the same pattern)","If the id is legacy, re-pin the key under a conforming id and republish"],"exampleFix":"// before\nawait buildEnvelope({ privateKey, keyId: 'my signing key', payload });\n// after\nconst keyId = process.env.CODEWHALE_FACTS_KEY_ID.trim();\nif (!KEY_ID_RE.test(keyId)) throw new Error(`bad key id: ${JSON.stringify(keyId)}`);\nawait buildEnvelope({ privateKey, keyId, payload });","handlingStrategy":"validation","validationCode":"import { KEY_ID_RE } from './facts-publish.mjs';\nif (typeof keyId !== 'string' || !KEY_ID_RE.test(keyId)) throw new Error(`keyId must match ${KEY_ID_RE}: got ${JSON.stringify(keyId)}`);","typeGuard":"const isValidKeyId = (k) => typeof k === 'string' && KEY_ID_RE.test(k);","tryCatchPattern":"try { env = buildEnvelope({ privateKey, keyId, payload }); } catch (e) { if (String(e.message).startsWith('key_id must match')) { console.error('Bad key id:', JSON.stringify(keyId)); process.exit(2); } throw e; }","preventionTips":["Trim and normalize key ids read from env/files before use","Store key ids only in one canonical place (the pin list) and reference them","Add a startup assertion that all configured ids match KEY_ID_RE","Never hand-type key ids; copy from validated config"],"tags":["validation","signing","key-id"],"backgroundTag":"invalid-identifier-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}