JuliusBrussee/caveman · error
cave_tool_definition_invalid
cave_tool_definition_invalid
Error message
cave_tool_definition_invalid
What it means
Thrown by visit in validateAgentGraph when an entry in an agent's tools array is not a valid tool declaration: it is null, its kind !== "tool", or its name is not a string. This validates each declared tool's basic shape before name/uniqueness/trust checks.
Solutions
- Ensure every tools entry is an object with kind: "tool" and a string name.
- Use the library's tool creation helper to build definitions rather than hand-writing plain objects.
- Filter or assert the tools array at construction time to drop undefined/null entries.
- Check imports — mixing tool shapes from incompatible library versions triggers this.
Example fix
// before
const root = { kind: "agent", tools: [searchFn] };
// after
const root = { kind: "agent", tools: [{ kind: "tool", name: "search", /* ... */ }] }; Defensive patterns
Strategy: validation
Validate before calling
function isValidToolDeclaration(t: unknown): t is ToolDefinition {
return typeof t === "object" && t !== null &&
(t as ToolDefinition).kind === "tool" &&
typeof (t as ToolDefinition).name === "string";
}
definition.tools.forEach((t, i) => { if (!isValidToolDeclaration(t)) throw new Error(`tools[${i}] is not a valid tool declaration`); }); Type guard
function isToolDefinition(v: unknown): v is ToolDefinition {
return typeof v === "object" && v !== null &&
(v as ToolDefinition).kind === "tool" &&
typeof (v as ToolDefinition).name === "string";
} Try / catch
try {
validateAgentGraph(def);
} catch (e) {
if (e instanceof Error && e.message === "cave_tool_definition_invalid") {
console.error("Every entry in tools must be an object with kind: 'tool' and a string name");
} else throw e;
} Prevention
- Build tools only via the library's tool factory helpers.
- Filter tools arrays (tools.filter(isToolDefinition)) before composing agents.
- Beware conditional spreads and failed factory calls that yield undefined entries.
When it happens
Trigger: Passing a raw function instead of a tool definition object, an object with kind omitted or misspelled, a tool built by a helper returning undefined on failure, or tools: [null] from a failed lookup.
Common situations: Refactoring tool factories so they sometimes return plain objects, importing tools from another library with a different shape, typos like type: "tool" instead of kind: "tool", or conditional spreads that drop required fields.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- canonical span
- cave_agent_definition_invalid
- cave_context_ir_invalid
- cave_duplicate_tool_name
- cave_output_schema_mismatch
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/ca05f7c116a9c47e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/definition-graph.ts:38
throw new Error("cave_agent_definition_invalid");
}
if (depth > 8) throw new Error("cave_subagent_depth_limit");
if (active.has(definition)) throw new Error("cave_subagent_definition_cycle");
// Host mode is an opt-in the root makes for itself. A descendant cannot use
// 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);View on GitHub (pinned to 3ee70a1026)