{"record":{"id":"0d5324862ca19811","repo":"JuliusBrussee/caveman","slug":"label-has-unsupported-algorithm-string-info-a","errorCode":null,"errorMessage":"${label} has unsupported algorithm ${String(info.alg)}","messagePattern":"(.+?) has unsupported algorithm (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":17849,"sourceCode":"  let prev: Receipt | undefined;\n  for (const r of sorted) {\n    const decoded = keys.get(r.signature?.key_id);\n    if (!decoded) return `seq ${r.seq}: no trusted public key for key_id ${String(r.signature?.key_id)}`;\n    const err = verifyReceipt(r, decoded.key, decoded.info.key_id);\n    if (err) return err;\n    if (prev) {\n      if (r.seq !== prev.seq + 1) return `seq ${r.seq}: not strictly after ${prev.seq}`;\n      if (r.prev_receipt_hash !== prev.receipt_hash) return `seq ${r.seq}: prev_receipt_hash does not link to seq ${prev.seq}`;\n      if (r.day <= prev.day) return `seq ${r.seq}: day ${r.day} does not follow ${prev.day}`;\n    }\n    prev = r;\n  }\n  return null;\n}\n\nfunction decodeReceiptKey(info: ReceiptPublicKey, label: string): DecodedReceiptKey {\n  if (!info || typeof info.key_id !== \"string\" || !info.key_id.trim()) throw new Error(`${label} key_id is required`);\n  if (info.alg !== \"Ed25519\") throw new Error(`${label} has unsupported algorithm ${String(info.alg)}`);\n  if (typeof info.key !== \"string\" || !info.key.trim()) throw new Error(`${label} key is required`);\n  const raw = Buffer.from(info.key, \"base64\");\n  if (raw.length !== 32 || raw.toString(\"base64\") !== info.key) throw new Error(`${label} must be a canonical base64 Ed25519 public key`);\n  return { info, raw, key: ed25519PublicKey(raw) };\n}\n\nfunction decodeUniqueKeyring(infos: ReceiptPublicKey[], label: string): Map<string, DecodedReceiptKey> {\n  const keys = new Map<string, DecodedReceiptKey>();\n  for (const [index, info] of infos.entries()) {\n    const decoded = decodeReceiptKey(info, `${label}[${index}]`);\n    if (keys.has(decoded.info.key_id)) throw new Error(`${label} contains duplicate key_id ${decoded.info.key_id}`);\n    keys.set(decoded.info.key_id, decoded);\n  }\n  return keys;\n}\n\nfunction embeddedReceiptKeys(bundle: ReceiptBundle): { current: DecodedReceiptKey; keys: Map<string, DecodedReceiptKey> } {\n  if (bundle.schema !== RECEIPT_BUNDLE_V1 && bundle.schema !== RECEIPT_BUNDLE_V2) throw new Error(`unsupported bundle schema ${String(bundle.schema)}`);","sourceCodeStart":17831,"sourceCodeEnd":17867,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L17831-L17867","documentation":"Thrown by decodeReceiptKey when the ReceiptPublicKey's alg field is anything other than the exact string \"Ed25519\". The receipt verifier only implements Ed25519 signature verification, so keys declared with another algorithm (or a differently cased/misspelled alg) are rejected outright.","triggerScenarios":"Verifying a bundle whose public key entry has alg set to e.g. 'ed25519' (lowercase), 'EdDSA', 'RSA', or is missing/null. Case-sensitive strict equality against 'Ed25519' is enforced.","commonSituations":"Generating keys with a JOSE/JWT library that uses alg 'EdDSA'; hand-writing bundle JSON with lowercase 'ed25519'; an exporter emitting 'ed25519' vs the verifier's 'Ed25519' convention.","solutions":["Set alg to exactly \"Ed25519\" (capital E, capital E, digits 25519) in the key entry.","Re-export the bundle using the official tooling so the algorithm field matches.","If your key genuinely is another algorithm, generate an Ed25519 key instead — the verifier supports nothing else."],"exampleFix":"// before\n{\"key_id\": \"k1\", \"alg\": \"ed25519\", \"key\": \"...\"}\n// after\n{\"key_id\": \"k1\", \"alg\": \"Ed25519\", \"key\": \"...\"}","handlingStrategy":"validation","validationCode":"if (info.alg !== 'Ed25519') throw new Error(`unsupported alg ${info.alg}; use Ed25519`);","typeGuard":"function isEd25519KeyInfo(info: unknown): info is { alg: 'Ed25519'; key: string; key_id: string } {\n  return typeof info === 'object' && info !== null && (info as any).alg === 'Ed25519';\n}","tryCatchPattern":"try {\n  verifyBundle(bundle);\n} catch (e) {\n  if ((e as Error).message.includes('unsupported algorithm')) console.error('only Ed25519 keys are supported (exact casing)');\n  throw e;\n}","preventionTips":["Use the literal string \"Ed25519\" — the check is case-sensitive.","Map JOSE 'EdDSA' keys to an 'Ed25519' alg label when exporting bundles.","Lint bundle JSON for allowed alg values before distribution."],"tags":["crypto","validation","enum"],"backgroundTag":"unsupported-enum-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}