{"record":{"id":"d7de81e2aff56591","repo":"JuliusBrussee/caveman","slug":"field-is-not-canonical-base64","errorCode":null,"errorMessage":"${field} is not canonical base64","messagePattern":"(.+?) is not canonical base64","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":12697,"sourceCode":"function mcpMarkerBytes(mcp: { command: string; args: string[] }, tool: string, configPath?: string): Buffer {\n  return Buffer.from(JSON.stringify({\n    ...(configPath ? { schema_version: 1 } : {}),\n    tool,\n    command: mcp.command,\n    args: mcp.args,\n    ...(configPath ? { config_path: canonicalMcpConfigPath(configPath) } : {}),\n  }, null, 2) + \"\\n\");\n}\n\nfunction validMcpMarkerBytes(bytes: Buffer, agent: \"kilo\" | \"qwen\", serverName: string): boolean {\n  return parseMcpServerMarkerBytes(agent, serverName, bytes) !== null;\n}\n\nfunction decodePendingBytes(value: unknown, field: string): Buffer | null {\n  if (value === null) return null;\n  if (typeof value !== \"string\") throw new Error(`${field} must be base64 or null`);\n  const bytes = Buffer.from(value, \"base64\");\n  if (bytes.toString(\"base64\") !== value) throw new Error(`${field} is not canonical base64`);\n  return bytes;\n}\n\nfunction validOptionalHash(value: unknown): value is string | null {\n  return value === null || (typeof value === \"string\" && /^sha256:[0-9a-f]{64}$/.test(value));\n}\n\ntype ReadOwnedMcpPendingJournal = {\n  journal: OwnedMcpPendingJournal;\n  configBefore: Buffer | null;\n  markerBefore: Buffer | null;\n  markerAfter: Buffer | null;\n  path: string;\n  bytes: Buffer;\n};\n\nfunction ownedMcpPendingLabel(agent?: string, serverName?: string): string {\n  return agent && serverName ? `${agent} ${serverName} MCP` : \"owned MCP\";","sourceCodeStart":12679,"sourceCodeEnd":12715,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L12679-L12715","documentation":"decodePendingBytes also requires base64 values to be canonical: re-encoding the decoded bytes must reproduce the original string exactly. Non-canonical forms (wrong padding, embedded whitespace, different alphabet usage) are rejected so journal integrity hashes compare deterministically.","triggerScenarios":"A journal file whose *_base64 field uses non-canonical base64: missing '=' padding, extra padding, line breaks or spaces inside the value, or base64url encoding instead of standard base64.","commonSituations":"Hand-copying a base64 blob from docs/logs into the journal; an external editor wrapping long lines; using a base64url encoder when standard base64 is expected.","solutions":["Re-encode the value canonically: Buffer.from(value,'base64') then .toString('base64'), and put the result in the journal","Remove whitespace/line breaks and fix '=' padding to the correct multiple of 4","Regenerate the journal by re-running the transaction rather than repairing by hand"],"exampleFix":"// before\n{ \"config_before_base64\": \"eyJhIjoxfQ\" } // missing padding\n// after\n{ \"config_before_base64\": \"eyJhIjoxfQ==\" }","handlingStrategy":"validation","validationCode":"function isCanonicalBase64(v: string): boolean {\n  return Buffer.from(v, 'base64').toString('base64') === v;\n}\n// check before writing/repairing journal fields\n['config_before_base64','marker_before_base64','marker_after_base64']\n  .forEach(k => { if (typeof j[k] === 'string' && !isCanonicalBase64(j[k])) throw new Error(k); });","typeGuard":"function isCanonicalBase64Value(v: unknown): v is string {\n  return typeof v === 'string' && Buffer.from(v, 'base64').toString('base64') === v;\n}","tryCatchPattern":"try {\n  decodePendingBytes(value, field);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('not canonical base64')) {\n    value = Buffer.from(value as string, 'base64').toString('base64'); // re-canonicalize\n  } else throw e;\n}","preventionTips":["Always produce base64 with standard encoding, no line wrapping","Fix padding: length must be a multiple of 4 with correct '='","Never paste base64 from sources that add whitespace; strip it first","Round-trip check (decode then re-encode) before persisting base64"],"tags":["validation","base64","journal","encoding"],"backgroundTag":"invalid-argument-format","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"}