JuliusBrussee/caveman · error
cave_agent_definition_invalid
cave_agent_definition_invalid
Error message
cave_agent_definition_invalid
What it means
Thrown by the visit closure in validateAgentGraph when an AgentDefinition is null, has kind !== "agent", or its tools field is not an array. It is the entry-point shape validation for the agent definition graph — the definition object is malformed before any deeper structural checks run.
Solutions
- Ensure the definition has kind: "agent" and tools as an array (use [] if there are no tools).
- Check that you are passing the AgentDefinition object itself, not a wrapper (e.g. { agent: def }).
- Log/inspect the definition passed in; null usually means a failed lookup or import.
- If definitions come from JSON config, validate them against the AgentDefinition schema before loading.
Example fix
// before
validateAgentGraph({ name: "root", tools: myTool });
// after
validateAgentGraph({ kind: "agent", name: "root", tools: [myTool] }); Defensive patterns
Strategy: validation
Validate before calling
function assertAgentDefinition(def: unknown): asserts def is AgentDefinition {
if (!def || (def as AgentDefinition).kind !== "agent" || !Array.isArray((def as AgentDefinition).tools)) {
throw new Error("definition must have kind: 'agent' and a tools array");
}
} Type guard
function isAgentDefinition(v: unknown): v is AgentDefinition {
return typeof v === "object" && v !== null &&
(v as AgentDefinition).kind === "agent" &&
Array.isArray((v as AgentDefinition).tools);
} Try / catch
try {
validateAgentGraph(definition);
} catch (e) {
if (e instanceof Error && e.message === "cave_agent_definition_invalid") {
console.error("Agent definition malformed: needs kind === 'agent' and tools: []");
} else throw e;
} Prevention
- Always include kind: "agent" and tools: [] even for tool-less agents.
- Validate definitions loaded from JSON against the schema before use.
- Check variable initialization — null usually means a failed import or lookup.
When it happens
Trigger: Calling validateAgentGraph (directly or through agent construction/run) with a definition that is undefined/null, an object whose kind is missing or not "agent", or one where tools was omitted, set to null, or set to a non-array value.
Common situations: Hand-written agent JSON missing the kind field, a typo like kinds: "agent", tools accidentally assigned a single tool object instead of an array, or a deserialized definition that lost fields during a version migration.
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_context_ir_invalid
- cave_output_schema_mismatch
- cave_output_schema_mismatch
- cave_sandbox_request_invalid
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/d0f457a5d1185db3.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/definition-graph.ts:20
const TOOL_IMPLEMENTATION_SOURCE = Symbol.for(
"@caveman-ai/agent:tool-implementation-source",
);
export function validateAgentGraph(root: AgentDefinition): void {
// Memoize per inherited containment posture: the same child definition
// reached under a sandbox-required ancestor must be re-checked, not skipped.
const visited = [new Set<AgentDefinition>(), new Set<AgentDefinition>()];
const active = new Set<AgentDefinition>();
const visit = (
definition: AgentDefinition,
depth: number,
sandboxRequired: boolean,
): void => {
if (!definition || definition.kind !== "agent" ||
!Array.isArray(definition.tools)) {
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");View on GitHub (pinned to 3ee70a1026)