{"record":{"id":"5f40da19b2e497d1","repo":"JuliusBrussee/caveman","slug":"cave-sandbox-unknown-subagent","errorCode":"cave_sandbox_unknown_subagent","errorMessage":"cave_sandbox_unknown_subagent","messagePattern":"cave_sandbox_unknown_subagent","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/tool-worker.ts","lineNumber":116,"sourceCode":"      !/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(request.tool) ||\n      typeof request.allowSideEffects !== \"boolean\" ||\n      typeof request.allowNetwork !== \"boolean\") {\n    throw new Error(\"cave_sandbox_request_invalid\");\n  }\n  if (request.allowNetwork !== true) installNetworkDeny();\n  const imported = await import(request.entry) as { default?: AgentDefinition; agent?: AgentDefinition };\n  let definition = imported.default ?? imported.agent;\n  if (!definition || definition.kind !== \"agent\") throw new Error(\"cave_sandbox_agent_export_missing\");\n  validateAgentGraph(definition);\n  if (agentDefinitionSHA256(definition) !== request.rootDefinitionSha256) {\n    throw new Error(\"cave_sandbox_definition_mismatch\");\n  }\n  const visited = new Set<AgentDefinition>([definition]);\n  for (const name of request.agentPath) {\n    const delegated = definition.tools.filter((item) =>\n      item.name === name && item.runtime?.kind === \"subagent\"\n    );\n    if (delegated.length !== 1) throw new Error(\"cave_sandbox_unknown_subagent\");\n    const child = delegated[0]!.runtime!.definition as AgentDefinition;\n    if (!child || child.kind !== \"agent\") {\n      throw new Error(\"cave_sandbox_subagent_definition_invalid\");\n    }\n    if (visited.has(child)) throw new Error(\"cave_sandbox_subagent_cycle\");\n    visited.add(child);\n    definition = child;\n  }\n  const selectedTools = definition.tools.filter((item) => item.name === request.tool);\n  if (selectedTools.length !== 1 || selectedTools[0]!.runtime?.kind === \"subagent\") {\n    throw new Error(\"cave_sandbox_unknown_tool\");\n  }\n  const selected = selectedTools[0]!;\n  if (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) {\n    throw new Error(\"cave_sandbox_tool_definition_mismatch\");\n  }\n  if (selected.effect !== \"read\" && request.allowSideEffects !== true) {\n    throw new Error(\"cave_sandbox_side_effect_denied\");","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/tool-worker.ts#L98-L134","documentation":"While walking request.agentPath from the root agent inward, the worker filters the current definition's tools for one whose name matches the path element AND whose runtime.kind is \"subagent\". If zero or more than one tool matches, the delegation path is invalid and the worker refuses to descend.","triggerScenarios":"agentPath names a tool that exists but is a normal tool (runtime.kind !== \"subagent\"); the name matches no tool at all; two subagent tools share the same name so `delegated.length !== 1`; a typo or renamed subagent in the path.","commonSituations":"Renaming a subagent tool without updating the path the parent recorded; duplicate tool names inside one agent's tools array (e.g. copy-pasted tool definitions); the parent's path was built against an older definition snapshot.","solutions":["Check the agent's tools array contains exactly one subagent-runtime tool with the path element's name.","Rename duplicates so every subagent tool name is unique within its parent definition.","Regenerate/re-derive agentPath after editing tool names, and re-run so the digest checks pass with the new graph."],"exampleFix":"// before\nconst tools = [subagent(\"research\", researchDef), subagent(\"research\", otherDef)]; // duplicate name\n\n// after\nconst tools = [subagent(\"research\", researchDef), subagent(\"research_alt\", otherDef)];","handlingStrategy":"validation","validationCode":"function resolveSubagent(def: AgentDefinition, name: string): AgentDefinition | null {\n  const matches = def.tools.filter((t) => t.name === name && t.runtime?.kind === \"subagent\");\n  return matches.length === 1 ? (matches[0].runtime!.definition as AgentDefinition) : null;\n}","typeGuard":"function hasUniqueSubagent(def: { tools: { name: string; runtime?: { kind?: string } }[] }, name: string): boolean {\n  return def.tools.filter((t) => t.name === name && t.runtime?.kind === \"subagent\").length === 1;\n}","tryCatchPattern":null,"preventionTips":["Enforce unique tool names per definition at build time.","Validate the full agentPath walk in the parent before spawning the worker."],"tags":["sandbox","subagent","delegation","cave"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}