{"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/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/tool-worker.ts#L63-L99","documentation":"The sandbox tool worker reads its request frame from stdin and enforces a hard 1,048,576-byte (1 MiB) limit; exceeding it throws cave_sandbox_input_limit before any parsing. The cap bounds worker memory and keeps the length-prefixed protocol cheap — oversized tool params are rejected up front rather than buffered.","triggerScenarios":"A sandboxed tool invocation whose serialized request frame (entry, agentPath, digests, tool name, and especially params) exceeds 1 MiB — e.g. passing a huge document, base64 blob, or large array as tool arguments.","commonSituations":"Feeding whole files or logs into a sandboxed tool's params instead of reading them inside the sandbox; pasting large inline data because the tool has no file-path parameter.","solutions":["Pass a file path (or digest/reference) instead of inline content, and let the sandboxed tool read the file itself.","Trim or chunk params so the JSON-serialized frame stays well under 1 MiB.","Move large payloads into the entry/definition bundle rather than the per-invocation request."],"exampleFix":"// before\nconst out = await tool({ data: hugeBase64String }); // > 1 MiB frame\n\n// after\nawait fs.writeFile(tmp, hugeBase64String);\nconst out = await tool({ dataPath: tmp });","handlingStrategy":"validation","validationCode":"const INPUT_LIMIT = 1_048_576;\nfunction withinSandboxInputLimit(request: unknown): boolean {\n  const size = Buffer.byteLength(JSON.stringify(request) ?? \"\", \"utf8\");\n  return size <= INPUT_LIMIT;\n}\nif (!withinSandboxInputLimit(frame)) throw new Error(\"params too large for sandbox worker\");","typeGuard":null,"tryCatchPattern":"try {\n  await invokeSandboxedTool(frame);\n} catch (error) {\n  if (error instanceof Error && error.message === \"cave_sandbox_input_limit\") {\n    // do not retry the same payload: pass a file reference instead of inline data\n  } else throw error;\n}","preventionTips":["Keep serialized tool params well under 1 MiB — the limit counts the whole request frame.","Pass file paths/digests for large data; read contents inside the sandbox.","Measure Buffer.byteLength(JSON.stringify(params)) when in doubt."],"tags":["sandbox","worker","limits","payload-size"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}