{"record":{"id":"d0f457a5d1185db3","repo":"JuliusBrussee/caveman","slug":"cave-agent-definition-invalid","errorCode":"cave_agent_definition_invalid","errorMessage":"cave_agent_definition_invalid","messagePattern":"cave_agent_definition_invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/definition-graph.ts","lineNumber":20,"sourceCode":"\nconst TOOL_IMPLEMENTATION_SOURCE = Symbol.for(\n  \"@caveman-ai/agent:tool-implementation-source\",\n);\n\nexport function validateAgentGraph(root: AgentDefinition): void {\n  // Memoize per inherited containment posture: the same child definition\n  // reached under a sandbox-required ancestor must be re-checked, not skipped.\n  const visited = [new Set<AgentDefinition>(), new Set<AgentDefinition>()];\n  const active = new Set<AgentDefinition>();\n\n  const visit = (\n    definition: AgentDefinition,\n    depth: number,\n    sandboxRequired: boolean,\n  ): void => {\n    if (!definition || definition.kind !== \"agent\" ||\n        !Array.isArray(definition.tools)) {\n      throw new Error(\"cave_agent_definition_invalid\");\n    }\n    if (depth > 8) throw new Error(\"cave_subagent_depth_limit\");\n    if (active.has(definition)) throw new Error(\"cave_subagent_definition_cycle\");\n    // Host mode is an opt-in the root makes for itself. A descendant cannot use\n    // it to run closures outside an ancestor's required containment.\n    if (sandboxRequired && definition.sandbox === \"host\") {\n      throw new Error(\"cave_host_sandbox_nested_under_required\");\n    }\n    const memo = visited[sandboxRequired ? 1 : 0]!;\n    if (memo.has(definition)) return;\n    active.add(definition);\n    const childSandboxRequired = sandboxRequired ||\n      definition.sandbox === \"required\";\n    const names = new Set<string>();\n    for (const declared of definition.tools) {\n      if (!declared || declared.kind !== \"tool\" ||\n          typeof declared.name !== \"string\") {\n        throw new Error(\"cave_tool_definition_invalid\");","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/definition-graph.ts#L2-L38","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvalidateAgentGraph({ name: \"root\", tools: myTool });\n// after\nvalidateAgentGraph({ kind: \"agent\", name: \"root\", tools: [myTool] });","handlingStrategy":"validation","validationCode":"function assertAgentDefinition(def: unknown): asserts def is AgentDefinition {\n  if (!def || (def as AgentDefinition).kind !== \"agent\" || !Array.isArray((def as AgentDefinition).tools)) {\n    throw new Error(\"definition must have kind: 'agent' and a tools array\");\n  }\n}","typeGuard":"function isAgentDefinition(v: unknown): v is AgentDefinition {\n  return typeof v === \"object\" && v !== null &&\n    (v as AgentDefinition).kind === \"agent\" &&\n    Array.isArray((v as AgentDefinition).tools);\n}","tryCatchPattern":"try {\n  validateAgentGraph(definition);\n} catch (e) {\n  if (e instanceof Error && e.message === \"cave_agent_definition_invalid\") {\n    console.error(\"Agent definition malformed: needs kind === 'agent' and tools: []\");\n  } else throw e;\n}","preventionTips":["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."],"tags":["validation","agent-definition","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}