{"record":{"id":"8b3159b87277a683","repo":"JuliusBrussee/caveman","slug":"cave-reserved-tool-name-declared-name","errorCode":null,"errorMessage":"cave_reserved_tool_name:${declared.name}","messagePattern":"cave_reserved_tool_name:(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/definition-graph.ts","lineNumber":43,"sourceCode":"    // 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\");\n      }\n      if (names.has(declared.name)) throw new Error(\"cave_duplicate_tool_name\");\n      names.add(declared.name);\n      if (declared.name.startsWith(\"cave_\")) {\n        throw new Error(`cave_reserved_tool_name:${declared.name}`);\n      }\n      if (typeof Reflect.get(declared, TOOL_IMPLEMENTATION_SOURCE) !== \"string\") {\n        throw new Error(`cave_untrusted_tool_definition:${declared.name}`);\n      }\n      if (declared.runtime?.kind !== \"subagent\") continue;\n      const child = declared.runtime.definition as AgentDefinition;\n      visit(child, depth + 1, childSandboxRequired);\n    }\n    active.delete(definition);\n    memo.add(definition);\n  };\n\n  visit(root, 0, false);\n}\n\n/**\n * True when any agent in the graph opts into host mode.\n *","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/definition-graph.ts#L25-L61","documentation":"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).","triggerScenarios":"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_'.","commonSituations":"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).","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."],"exampleFix":"// before\nconst tools = [tool({ name: \"cave_search\", /* ... */ })];\n\n// after\nconst tools = [tool({ name: \"project_search\", /* ... */ })];","handlingStrategy":"validation","validationCode":"const RESERVED = \"cave_\";\nfunction hasReservedToolName(tools: { name: string }[]): string | undefined {\n  return tools.find((t) => t.name.startsWith(RESERVED))?.name;\n}\n// before validateAgentGraph:\nconst bad = hasReservedToolName(agentDef.tools);\nif (bad) throw new Error(`rename tool '${bad}': cave_ prefix is reserved`);","typeGuard":"function isSafeToolName(name: string): boolean {\n  return typeof name === \"string\" && name.length > 0 && !name.startsWith(\"cave_\");\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["validation","naming","agent-graph","reserved-prefix"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}