{"record":{"id":"33ae5f3b1f108c5a","repo":"JuliusBrussee/caveman","slug":"cave-sandbox-request-invalid","errorCode":"cave_sandbox_request_invalid","errorMessage":"cave_sandbox_request_invalid","messagePattern":"cave_sandbox_request_invalid","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/tool-worker.ts","lineNumber":101,"sourceCode":"  }\n  return JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n}\n\ntry {\n  const request = await readRequest();\n  if (typeof request.entry !== \"string\" || !Array.isArray(request.agentPath) ||\n      request.agentPath.length > 8 ||\n      request.agentPath.some((item) => typeof item !== \"string\" ||\n        !/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(item)) ||\n      typeof request.rootDefinitionSha256 !== \"string\" ||\n      !/^[a-f0-9]{64}$/.test(request.rootDefinitionSha256) ||\n      typeof request.toolDefinitionSha256 !== \"string\" ||\n      !/^[a-f0-9]{64}$/.test(request.toolDefinitionSha256) ||\n      typeof request.tool !== \"string\" ||\n      !/^[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\");","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/tool-worker.ts#L83-L119","documentation":"The tool worker validates the stdin request frame against a strict shape before doing anything: `entry` must be a string; `agentPath` an array of at most 8 strings matching /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/; both digests 64-char lowercase hex; `tool` a name-shaped string; and `allowSideEffects`/`allowNetwork` booleans. Any deviation throws cave_sandbox_request_invalid — the protocol fails closed on malformed input because the worker is a trust boundary.","triggerScenarios":"A parent runtime and worker built from mismatched versions exchanging different frame schemas; a hand-rolled or corrupted stdin write to the worker; agentPath longer than 8 levels or containing invalid characters.","commonSituations":"Version drift after a partial upgrade of @caveman-ai/agent (stale compiled worker, mixed node_modules); invoking the worker binary directly for testing with an ad-hoc JSON payload; deeply nested subagent paths exceeding the depth-8 path cap.","solutions":["Reinstall/rebuild so the runtime and tool worker come from the same package version.","If invoking the worker manually, replicate the documented frame exactly (string entry, ≤8-segment agentPath, 64-hex digests, name-shaped tool, boolean flags).","Reduce subagent nesting depth so agentPath stays within 8 segments."],"exampleFix":"// before: manual test frame\n{ entry: 42, agentPath: [\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\"], ... }\n\n// after\n{ entry: \"./dist/agent.js\", agentPath: [\"a\",\"b\"], rootDefinitionSha256: \"<64 hex>\", toolDefinitionSha256: \"<64 hex>\", tool: \"myTool\", params: {}, allowSideEffects: false, allowNetwork: false }","handlingStrategy":"type-guard","validationCode":"function isHex64(v: unknown): v is string { return typeof v === \"string\" && /^[a-f0-9]{64}$/.test(v); }\nconst NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/;","typeGuard":"type SandboxRequest = { entry: string; agentPath: string[]; rootDefinitionSha256: string; toolDefinitionSha256: string; tool: string; params: unknown; allowSideEffects: boolean; allowNetwork: boolean };\nfunction isSandboxRequest(r: unknown): r is SandboxRequest {\n  if (typeof r !== \"object\" || r === null) return false;\n  const v = r as Record<string, unknown>;\n  return typeof v.entry === \"string\" &&\n    Array.isArray(v.agentPath) && v.agentPath.length <= 8 &&\n    v.agentPath.every((s) => typeof s === \"string\" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(s)) &&\n    typeof v.rootDefinitionSha256 === \"string\" && /^[a-f0-9]{64}$/.test(v.rootDefinitionSha256) &&\n    typeof v.toolDefinitionSha256 === \"string\" && /^[a-f0-9]{64}$/.test(v.toolDefinitionSha256) &&\n    typeof v.tool === \"string\" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(v.tool) &&\n    typeof v.allowSideEffects === \"boolean\" && typeof v.allowNetwork === \"boolean\";\n}","tryCatchPattern":"try {\n  await runWorker(frame);\n} catch (error) {\n  if (error instanceof Error && error.message === \"cave_sandbox_request_invalid\") {\n    // frame rejected at the trust boundary: check schema and version parity, never resend unchanged\n  } else throw error;\n}","preventionTips":["Keep runtime and tool worker on the same package version — reinstall after upgrades.","Validate hand-built frames with the full shape guard before writing to the worker's stdin.","Keep agentPath at most 8 segments and tool/agent names matching [a-zA-Z][a-zA-Z0-9_-]{0,127}."],"tags":["sandbox","worker","protocol","validation","version-drift"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}