JuliusBrussee/caveman · warning
cave_recovery_handle_out_of_scope
Error message
cave_recovery_handle_out_of_scope
What it means
Thrown by the cave_retrieve tool when the model supplies a recovery_handle that is not in this run's handle set. Handles are deliberately scoped to a single run (see the tool description) so omitted content cannot be pulled back with stale or foreign handles.
Source
Thrown at packages/agent/src/runtime.ts:3041
}
function recoveryTool(
handles: ReadonlySet<string>,
engineBin: string | undefined,
trace?: MutableTransformTrace[],
): AgentTool<TSchema> {
return {
name: "cave_retrieve",
label: "cave_retrieve",
description: "Recover exact content omitted by an active Caveman transform. Handles are scoped to this run.",
parameters: Type.Object({
recovery_handle: Type.String(),
query: Type.Optional(Type.String()),
}),
executionMode: "parallel",
async execute(_toolCallId, params) {
const input = params as { recovery_handle: string; query?: string };
if (!handles.has(input.recovery_handle)) throw new Error("cave_recovery_handle_out_of_scope");
const value = await engineRetrieve(input.recovery_handle, input.query, engineBin);
for (const item of trace ?? []) {
if (item.recoveryHandle === input.recovery_handle) item.recoveryUsed = true;
}
return {
content: [{ type: "text", text: new TextDecoder().decode(value) }],
details: { recovery: input.query ? "query" : "exact" },
};
},
};
}
function toolSchemaSearchTool(
handles: ReadonlySet<string>,
engineBin: string | undefined,
trace?: MutableTransformTrace[],
): AgentTool<TSchema> {
return {View on GitHub (pinned to 27d5a3981a)
Solutions
- No code fix needed for correctness — the guard is the fix; but reduce occurrences: avoid replaying prior-run transcripts that contain stale handles into the model's context
- If resuming conversations, start a fresh run so the model never sees handles that expired
- Sanitize few-shot examples so they don't include realistic-looking handle strings the model will imitate
Defensive patterns
Strategy: try-catch
Type guard
function isHandleOutOfScope(e: unknown): e is Error {
return e instanceof Error && e.message === "cave_recovery_handle_out_of_scope";
} Try / catch
// Inside tool-result handling:
try {
const out = await caveRetrieve.execute(callId, { recovery_handle: h });
} catch (e) {
if (isHandleOutOfScope(e)) {
// return a tool error telling the model the handle expired for this run
} else throw e;
} Prevention
- Start a fresh run when resuming conversations so stale handles never enter context
- Strip previous-run tool transcripts (with handles) from replayed history
- Sanitize few-shot examples so they contain no realistic handle strings
When it happens
Trigger: The model calls cave_retrieve with a handle from a previous run, a hallucinated/invented handle string, or a handle from a different segment than those registered for this run.
Common situations: Conversation replay/resume where the model remembers old handles; models hallucinating handle strings; prompts containing example handles the model copies.
Related errors
- engine_changed_bytes_without_recovery
- cannot read pending ${agent} agent-native bundle journal: ${
- cannot read pending ${agent} agent-native removal journal: $
- ${skill.file} changed during interrupted setup; refusing des
- ${agent} caveman-cloud MCP changed during interrupted setup;
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/3aad056e596d5cdd.
Report an issue: GitHub.