JuliusBrussee/caveman · error

cave_sandbox_unknown_subagent

cave_sandbox_unknown_subagent

Error message

cave_sandbox_unknown_subagent

What it means

While walking request.agentPath (the chain of subagent delegations from the root definition to the tool's owning agent), the worker filters the current definition's tools for one with the given name AND `runtime.kind === "subagent"`. If the filter does not yield exactly one match, it throws `cave_sandbox_unknown_subagent`. The parent's delegation path must be exactly reproducible from the definitions the worker imported.

Solutions

  1. Ensure every tool name within an agent definition is unique; rename duplicated tools.
  2. Regenerate the delegation path from the current definition (re-run build) so agentPath matches the imported graph.
  3. Verify each name in agentPath refers to a tool whose runtime.kind is exactly "subagent".
  4. Fix typos/renames so the nested tool name in the path matches the definition.

Example fix

// before
tools: [subagentTool("delegate", childA), subagentTool("delegate", childB)]

// after
tools: [subagentTool("delegate_to_a", childA), subagentTool("delegate_to_b", childB)]
Defensive patterns

Strategy: validation

Validate before calling

// Verify each hop of the delegation path resolves to exactly one subagent tool
let def = rootDefinition;
for (const name of agentPath) {
  const matches = def.tools.filter((t) => t.name === name && t.runtime?.kind === "subagent");
  if (matches.length !== 1) throw new Error(`agentPath hop '${name}' does not resolve to exactly one subagent`);
  def = matches[0]!.runtime!.definition as AgentDefinition;
}

Type guard

const isSubagentTool = (t: unknown): t is { name: string; runtime: { kind: "subagent"; definition: AgentDefinition } } =>
  typeof t === "object" && t !== null &&
  (t as any).runtime?.kind === "subagent" &&
  Boolean((t as any).runtime.definition);

Prevention

When it happens

Trigger: request.agentPath names a tool that does not exist on the current definition, exists but is not a subagent-runtime tool, or exists as multiple tools with the same name at that level (zero or >1 subagent matches).

Common situations: Duplicate tool names in an agent definition (two tools registered under one name); the path was computed against an older definition version while the entry module now differs; a typo or rename in a nested tool name; a plain (non-subagent) tool mistakenly listed in agentPath.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/5f40da19b2e497d1. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/tool-worker.ts:116

      !/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(request.tool) ||
      typeof request.allowSideEffects !== "boolean" ||
      typeof request.allowNetwork !== "boolean") {
    throw new Error("cave_sandbox_request_invalid");
  }
  if (request.allowNetwork !== true) installNetworkDeny();
  const imported = await import(request.entry) as { default?: AgentDefinition; agent?: AgentDefinition };
  let definition = imported.default ?? imported.agent;
  if (!definition || definition.kind !== "agent") throw new Error("cave_sandbox_agent_export_missing");
  validateAgentGraph(definition);
  if (agentDefinitionSHA256(definition) !== request.rootDefinitionSha256) {
    throw new Error("cave_sandbox_definition_mismatch");
  }
  const visited = new Set<AgentDefinition>([definition]);
  for (const name of request.agentPath) {
    const delegated = definition.tools.filter((item) =>
      item.name === name && item.runtime?.kind === "subagent"
    );
    if (delegated.length !== 1) throw new Error("cave_sandbox_unknown_subagent");
    const child = delegated[0]!.runtime!.definition as AgentDefinition;
    if (!child || child.kind !== "agent") {
      throw new Error("cave_sandbox_subagent_definition_invalid");
    }
    if (visited.has(child)) throw new Error("cave_sandbox_subagent_cycle");
    visited.add(child);
    definition = child;
  }
  const selectedTools = definition.tools.filter((item) => item.name === request.tool);
  if (selectedTools.length !== 1 || selectedTools[0]!.runtime?.kind === "subagent") {
    throw new Error("cave_sandbox_unknown_tool");
  }
  const selected = selectedTools[0]!;
  if (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) {
    throw new Error("cave_sandbox_tool_definition_mismatch");
  }
  if (selected.effect !== "read" && request.allowSideEffects !== true) {
    throw new Error("cave_sandbox_side_effect_denied");

View on GitHub (pinned to 3ee70a1026)