JuliusBrussee/caveman · error · Error
cave_reserved_tool_name:${declared.name}
Error message
cave_reserved_tool_name:${declared.name} What it means
Thrown by validateAgentGraph (packages/agent/src/definition-graph.ts:43) while recursively validating an agent definition graph: a declared tool's name starts with the framework-reserved prefix 'cave_'. The framework reserves that prefix for its own built-in tools so user tools can never impersonate framework tools anywhere in the agent tree (root or subagent).
Source
Thrown at packages/agent/src/definition-graph.ts:43
// it to run closures outside an ancestor's required containment.
if (sandboxRequired && definition.sandbox === "host") {
throw new Error("cave_host_sandbox_nested_under_required");
}
const memo = visited[sandboxRequired ? 1 : 0]!;
if (memo.has(definition)) return;
active.add(definition);
const childSandboxRequired = sandboxRequired ||
definition.sandbox === "required";
const names = new Set<string>();
for (const declared of definition.tools) {
if (!declared || declared.kind !== "tool" ||
typeof declared.name !== "string") {
throw new Error("cave_tool_definition_invalid");
}
if (names.has(declared.name)) throw new Error("cave_duplicate_tool_name");
names.add(declared.name);
if (declared.name.startsWith("cave_")) {
throw new Error(`cave_reserved_tool_name:${declared.name}`);
}
if (typeof Reflect.get(declared, TOOL_IMPLEMENTATION_SOURCE) !== "string") {
throw new Error(`cave_untrusted_tool_definition:${declared.name}`);
}
if (declared.runtime?.kind !== "subagent") continue;
const child = declared.runtime.definition as AgentDefinition;
visit(child, depth + 1, childSandboxRequired);
}
active.delete(definition);
memo.add(definition);
};
visit(root, 0, false);
}
/**
* True when any agent in the graph opts into host mode.
*View on GitHub (pinned to 27d5a3981a)
Solutions
- Rename the offending tool (named in the message after the colon) to anything that does not start with 'cave_'.
- If you built the AgentDefinition object literally instead of via agent(), prefer the agent() builder so reserved-prefix and duplicate checks fire at construction time with clearer errors.
- Re-run validateAgentGraph to confirm no other tool in the nested tree has the prefix.
Example fix
// before
const tools = [tool({ name: "cave_search", /* ... */ })];
// after
const tools = [tool({ name: "project_search", /* ... */ })]; Defensive patterns
Strategy: validation
Validate before calling
const RESERVED = "cave_";
function hasReservedToolName(tools: { name: string }[]): string | undefined {
return tools.find((t) => t.name.startsWith(RESERVED))?.name;
}
// before validateAgentGraph:
const bad = hasReservedToolName(agentDef.tools);
if (bad) throw new Error(`rename tool '${bad}': cave_ prefix is reserved`); Type guard
function isSafeToolName(name: string): boolean {
return typeof name === "string" && name.length > 0 && !name.startsWith("cave_");
} Prevention
- Create tools only via tool()/subagent() so agent() rejects reserved names at construction time.
- Add a lint rule or unit test asserting no project tool name starts with 'cave_'.
- Recursively check nested subagent definitions, not just the root tool list.
When it happens
Trigger: Calling validateAgentGraph (directly or via compile/dev/build, which validate the graph) on an AgentDefinition whose tools array — at any depth of nested subagent definitions — contains a tool whose name begins with 'cave_'.
Common situations: Copying a framework tool name when adding a wrapper tool; naming a custom tool like 'cave_search' or 'cave_retrieve'; injecting a tool into a nested subagent definition built by hand instead of via the builder API (agent() catches this earlier at index.ts:111, so hitting this deeper check usually means a hand-constructed definition object).
Related errors
- caveman agent: tool prefix cave_ is reserved by framework ($
- cave_duplicate_tool_name
- cave_untrusted_tool_definition:${declared.name}
- caveman agent: invalid agent id ${JSON.stringify(options.id)
- caveman agent: duplicate tool name
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/8b3159b87277a683.
Report an issue: GitHub.