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

  1. 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
  2. If resuming conversations, start a fresh run so the model never sees handles that expired
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/3aad056e596d5cdd. Report an issue: GitHub.