{"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/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/tool-worker.ts#L83-L119","documentation":"The tool worker validates the request envelope it reads from stdin before doing anything: entry must be a string, toolDefinitionSha256 must be a 64-char lowercase hex string, tool must match /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/, and allowSideEffects/allowNetwork must be booleans. Any violation throws `cave_sandbox_request_invalid`. This is fail-closed protocol validation between the parent runtime and the sandboxed worker.","triggerScenarios":"The parent runtime sends a malformed spawn request: missing field, undefined allowSideEffects/allowNetwork, a tool name that is empty, starts with a digit, contains invalid characters, or exceeds 128 chars, or a non-hex/wrong-length tool digest.","commonSituations":"Version skew between parent runtime and worker code (one changed the request schema); hand-crafted or replayed worker requests in custom harnesses; a tool name from dynamic data that violates the identifier pattern (e.g. contains a dot or starts with `_`); JSON coercion turning a boolean field into a string.","solutions":["Check that parent runtime and worker come from the same package version; reinstall/align @caveman-ai/agent so the request schema matches.","Fix the tool name: use only [A-Za-z0-9_-], starting with a letter, at most 128 characters, and not framework-reserved `cave_`.","Ensure toolDefinitionSha256 is produced by toolDefinitionSHA256 (64 lowercase hex) rather than hand-supplied.","If you spawn the worker yourself, pass allowSideEffects and allowNetwork as real booleans (never undefined/strings)."],"exampleFix":"// before\nspawnWorker({ tool: \"my.tool\", toolDefinitionSha256: sha, allowSideEffects: \"yes\", allowNetwork: 0 });\n\n// after\nspawnWorker({ tool: \"my_tool\", toolDefinitionSha256: sha256Hex, allowSideEffects: true, allowNetwork: false });","handlingStrategy":"validation","validationCode":"const TOOL_NAME = /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/;\nconst SHA256 = /^[a-f0-9]{64}$/;\nfunction isValidWorkerRequest(r: unknown): boolean {\n  const q = r as Record<string, unknown>;\n  return typeof q.entry === \"string\" &&\n    typeof q.toolDefinitionSha256 === \"string\" && SHA256.test(q.toolDefinitionSha256) &&\n    typeof q.tool === \"string\" && TOOL_NAME.test(q.tool) &&\n    typeof q.allowSideEffects === \"boolean\" &&\n    typeof q.allowNetwork === \"boolean\";\n}","typeGuard":"const isWorkerRequest = (r: unknown): r is ToolWorkerRequest =>\n  typeof r === \"object\" && r !== null &&\n  typeof (r as any).entry === \"string\" &&\n  typeof (r as any).toolDefinitionSha256 === \"string\" && /^[a-f0-9]{64}$/.test((r as any).toolDefinitionSha256) &&\n  typeof (r as any).tool === \"string\" && /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test((r as any).tool) &&\n  typeof (r as any).allowSideEffects === \"boolean\" &&\n  typeof (r as any).allowNetwork === \"boolean\";","tryCatchPattern":"try {\n  const result = await spawnToolWorker(request);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"cave_sandbox_request_invalid\")) {\n    console.error(\"worker request failed schema validation — check tool name, sha256, and boolean flags\");\n  }\n  throw err;\n}","preventionTips":["Keep parent runtime and worker on the exact same package version to avoid schema skew.","Name tools with letters, digits, `_`, `-` only, starting with a letter, max 128 chars.","Always derive toolDefinitionSha256 from toolDefinitionSHA256, never hand-write digests.","Pass allowSideEffects/allowNetwork as explicit booleans when constructing spawn requests."],"tags":["sandbox","validation","ipc","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"}