{"record":{"id":"d546126d385809cf","repo":"JuliusBrussee/caveman","slug":"cave-sandbox-input-limit","errorCode":"cave_sandbox_input_limit","errorMessage":"cave_sandbox_input_limit","messagePattern":"cave_sandbox_input_limit","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/tool-worker.ts","lineNumber":81,"sourceCode":"  process.exit(1);\n});\n\nasync function readRequest(): Promise<{\n  entry: string;\n  agentPath: string[];\n  rootDefinitionSha256: string;\n  toolDefinitionSha256: string;\n  tool: string;\n  params: unknown;\n  allowSideEffects: boolean;\n  allowNetwork: boolean;\n}> {\n  const chunks: Buffer[] = [];\n  let size = 0;\n  for await (const chunk of stdin) {\n    const buffer = Buffer.from(chunk);\n    size += buffer.byteLength;\n    if (size > 1_048_576) throw new Error(\"cave_sandbox_input_limit\");\n    chunks.push(buffer);\n  }\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\" ||","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/tool-worker.ts#L63-L99","documentation":"The sandboxed tool worker reads its JSON request from stdin and enforces a hard 1 MiB (1_048_576 byte) input ceiling. If the parent sends a request larger than that, readRequest throws `cave_sandbox_input_limit`. This bounds worker memory and prevents oversized payloads from being silently buffered.","triggerScenarios":"A tool invocation whose request envelope (arguments, nested agent definitions, agentPath, entry metadata) exceeds 1 MiB when serialized to the worker over stdin.","commonSituations":"Passing very large blobs (embedded files, big JSON documents, base64 images) directly as tool arguments instead of via file paths; an agent definition graph bloated with inline data reaching the worker; a caller accidentally serializing entire datasets into tool arguments.","solutions":["Reduce the tool arguments: pass a file path and let the tool read the data itself instead of embedding content in the request.","Move large inline definition data into separate files so the agent graph sent to the worker stays under 1 MiB.","Compress or truncate the payload before invocation (e.g. send a digest/handle, stream the data another way).","If the payload is legitimately near the limit, restructure the tool to accept smaller incremental chunks across multiple calls."],"exampleFix":"// before\nawait tools.search({ documents: hugeJsonString });\n\n// after\nawait tools.search({ documentsPath: \"./data/documents.json\" });","handlingStrategy":"validation","validationCode":"const MAX_WORKER_INPUT = 1_048_576;\nconst bytes = Buffer.byteLength(JSON.stringify(toolRequest), \"utf8\");\nif (bytes > MAX_WORKER_INPUT) {\n  throw new Error(`tool request ${bytes} bytes exceeds 1 MiB worker input limit; pass a file path instead`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await invokeSandboxedTool(tool, args);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"cave_sandbox_input_limit\")) {\n    return invokeSandboxedTool(tool, await offloadLargeArgsToFiles(args));\n  }\n  throw err;\n}","preventionTips":["Never embed large blobs (files, base64, big JSON) in tool arguments; pass paths and let the tool read them.","Keep agent definitions free of inline data payloads; move data to separate files.","Estimate the serialized request size in dev/CI for your heaviest tools.","Design tools around digests/handles plus incremental reads rather than whole-dataset arguments."],"tags":["sandbox","limit","payload","ipc"],"backgroundTag":"payload-too-large","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"}