JuliusBrussee/caveman · critical · Error
cave_runtime_segment_id_collision
cave_runtime_segment_id_collision
Error message
cave_runtime_segment_id_collision
What it means
When a runtime segment is lowered into the Context IR, segment identity is content-derived: if a segment id already exists, it must carry the same sha256 digest. The same id with different bytes means the id was reused for new content — exactly the confusion that once let compaction substitute an OLD message's compressed body into a NEW message — so the library fails closed instead of poisoning the CCR restore map.
Source
Thrown at packages/agent/src/context-ir.ts:287
return { ir: { schemaVersion: 1, segments }, bodies };
}
export function appendRuntimeContextSegment(
lowered: LoweredContext,
segment: RuntimeContextSegment,
): ContextSegment {
const digest = sha256(segment.body);
const existing = lowered.ir.segments.find((item) => item.id === segment.id);
if (existing) {
// Segment identity is content-derived, so the same id must
// carry the same bytes. If it does not, the id has been reused for
// different content — the exact confusion that once let compaction
// substitute an OLD message's compressed body into a NEW message. Fail
// closed rather than returning the stale segment and poisoning the CCR
// restore map.
if (existing.provenanceDigest !== digest) {
throw new Error("cave_runtime_segment_id_collision");
}
return existing;
}
const bodyHandle = `cave_local_sha256:${digest}`;
(lowered.bodies as Map<string, Uint8Array>).set(bodyHandle, segment.body.slice());
const appended: ContextSegment = {
id: segment.id,
kind: segment.kind,
stability: "turn",
safety: "S4",
priority: "normal",
recovery: "exact_ccr",
cacheRegion: "live_zone",
privacy: "local_sensitive",
opaque: opaquePayload(segment.body),
provenanceDigest: digest,
tokenCount: estimateTokens(segment.body),
bodyHandle,View on GitHub (pinned to 766dce6b13)
Solutions
- Derive ids from content, e.g. include the digest: `id: 'tool-result-' + digest.slice(0, 16)`.
- Never mutate a segment's body after adding it; add a new segment with a new id instead.
- Start a fresh lowered context when content identity changes rather than reusing ids.
Example fix
// before
const id = `tool-result-${index}`; // same id, new bytes on retry
// after
const digest = sha256(body);
const id = `tool-result-${digest.slice(0, 16)}`; // id changes with content Defensive patterns
Strategy: try-catch
Try / catch
try {
await withContextSegments(segments); // lowering/addition of runtime segments
} catch (error) {
if (error instanceof Error && error.message === "cave_runtime_segment_id_collision") {
throw new Error(
"segment id reused for different content: regenerate ids from the content digest",
);
}
throw error;
} Prevention
- Derive segment ids from content (include the sha256 digest) so a body change changes the id.
- Treat segment bodies as immutable once lowered; add a new segment instead of editing one.
When it happens
Trigger: Appending a segment whose id matches an existing one while its body changed: sequentially generated ids like `tool-result-1` reused after content updates, or a retry that regenerates output under the same id within one context build.
Common situations: Custom id schemes that aren't content-derived; caching layers that reuse keys across content versions; mutating a segment body after it was already lowered into the IR.
Related errors
- cave_harness_context_ir_mismatch
- cave_harness_incomplete_evidence
- cave_harness_model_identity_missing
- cave_context_ir_invalid
- cave_execution_plan_selection_mismatch
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/38f4499a967e878a.
Report an issue: GitHub.