{"record":{"id":"1708b9b7400b108b","repo":"JuliusBrussee/caveman","slug":"cave-context-ir-invalid","errorCode":"cave_context_ir_invalid","errorMessage":"cave_context_ir_invalid","messagePattern":"cave_context_ir_invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/context-ir.ts","lineNumber":85,"sourceCode":"      stability: segment.stability,\n      safety: segment.safety,\n      priority: segment.priority,\n      recovery: segment.recovery,\n      cache_region: segment.cacheRegion,\n      privacy: segment.privacy,\n      opaque: segment.opaque,\n      ...(segment.ttlTurns === undefined ? {} : { ttl_turns: segment.ttlTurns }),\n      provenance_digest: segment.provenanceDigest,\n      token_count: segment.tokenCount,\n      body_handle: segment.bodyHandle,\n    })),\n  };\n}\n\nexport function contextIRFromWire(value: unknown): ContextIR {\n  if (!isRecord(value) || !exactKeys(value, [\"schema_version\", \"segments\"]) ||\n      value.schema_version !== 1 || !Array.isArray(value.segments)) {\n    throw new Error(\"cave_context_ir_invalid\");\n  }\n  const segments = value.segments.map((item): ContextSegment => {\n    const required = [\n      \"id\", \"kind\", \"stability\", \"safety\", \"priority\", \"recovery\", \"cache_region\",\n      \"privacy\", \"opaque\", \"provenance_digest\", \"token_count\", \"body_handle\",\n    ];\n    if (!isRecord(item) ||\n        !(exactKeys(item, required) || exactKeys(item, [...required, \"ttl_turns\"])) ||\n        typeof item.id !== \"string\" || item.id.length === 0 ||\n        !known(item.kind, [\"instruction\", \"user_intent\", \"tool_schema\", \"skill\", \"memory\", \"history\", \"tool_result\", \"artifact\", \"error\", \"output_contract\"]) ||\n        !known(item.stability, [\"build\", \"session\", \"turn\"]) ||\n        !known(item.safety, [\"S0\", \"S1\", \"S2\", \"S3\", \"S4\"]) ||\n        !known(item.priority, [\"required\", \"high\", \"normal\", \"low\"]) ||\n        !known(item.recovery, [\"none\", \"exact_ccr\", \"source_ref\", \"recompute\"]) ||\n        !known(item.cache_region, [\"frozen_prefix\", \"live_zone\", \"uncached\"]) ||\n        !known(item.privacy, [\"content_blind\", \"local_sensitive\", \"connected_allowed\"]) ||\n        typeof item.opaque !== \"boolean\" ||\n        !/^[0-9a-f]{64}$/.test(String(item.provenance_digest)) ||","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/context-ir.ts#L67-L103","documentation":"contextIRFromWire is the deserialization boundary for the Context IR format. The envelope must be a record with exactly the keys schema_version and segments, schema_version must be 1, and segments must be an array. Any other shape — including forward-compatible future versions — is rejected as cave_context_ir_invalid.","triggerScenarios":"Feeding contextIRFromWire JSON that: is not an object; carries extra top-level keys; has schema_version 2 or '1' (string); has segments as an object rather than array; or was double-encoded (a JSON string of JSON).","commonSituations":"Persisted IR from a newer/older package version with a different schema_version; hand-crafted fixtures in tests; payloads relayed through queues that JSON.stringify twice; renamed top-level fields during refactors.","solutions":["Regenerate the wire payload with contextIRToWire from the same package version and retry","Pin all services that exchange Context IR to the same package version so schema_version matches","Parse the JSON once before passing (typeof value === 'string' ? JSON.parse(value) : value)","Add a version dispatch layer: read schema_version first and migrate older shapes before calling contextIRFromWire"],"exampleFix":"// before\nconst ir = contextIRFromWire(raw); // raw had schema_version: 2 or extra keys\n\n// after: re-serialize with the current codec\nconst wire = contextIRToWire(ir);\nconst roundTripped = contextIRFromWire(JSON.parse(JSON.stringify(wire)));","handlingStrategy":"type-guard","validationCode":"function looksLikeContextIREnvelope(v: unknown): boolean {\n  return typeof v === \"object\" && v !== null &&\n    Object.keys(v).length === 2 &&\n    (v as any).schema_version === 1 &&\n    Array.isArray((v as any).segments);\n}","typeGuard":"function isContextIRWire(v: unknown): v is { schema_version: 1; segments: unknown[] } {\n  return isRecord(v) &&\n    exactKeysCheck(v, [\"schema_version\", \"segments\"]) &&\n    v.schema_version === 1 && Array.isArray(v.segments);\n}","tryCatchPattern":"try {\n  const ir = contextIRFromWire(payload);\n} catch (err) {\n  if (err instanceof Error && err.message === \"cave_context_ir_invalid\") {\n    // treat as a version/shape mismatch: regenerate payload with contextIRToWire\n    throw new Error(`Context IR payload rejected; regenerate with the current codec (schema_version=${(payload as any)?.schema_version})`);\n  }\n  throw err;\n}","preventionTips":["Round-trip payloads through contextIRToWire/contextIRFromWire from the same package version","Pin package versions across all services exchanging Context IR","Parse JSON exactly once before deserialization"],"tags":["serialization","validation","schema-version","wire-format"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}