{"record":{"id":"8c582e4f9cdffcf7","repo":"JuliusBrussee/caveman","slug":"cave-sandbox-tool-failed","errorCode":"cave_sandbox_tool_failed","errorMessage":"cave_sandbox_tool_failed","messagePattern":"cave_sandbox_tool_failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":4866,"sourceCode":"          reject(new Error(`cave_sandbox_failed:${redactSandboxError(Buffer.concat(stderr).toString(\"utf8\"))}`));\n          return;\n        }\n        reject(new Error(\"cave_sandbox_invalid_output\"));\n      });\n      combined.addEventListener(\"abort\", onAbort, { once: true });\n      if (combined.aborted) onAbort();\n      child.stdin.end(JSON.stringify({\n        entry: pathToFileURL(entryPath).href,\n        agentPath: executionContext.agentPath,\n        rootDefinitionSha256: executionContext.rootDefinitionSha256,\n        toolDefinitionSha256,\n        tool: toolName,\n        params,\n        allowSideEffects,\n        allowNetwork: profile?.network === true,\n      }));\n    });\n    if (!result.ok) throw new Error(result.code ?? \"cave_sandbox_tool_failed\");\n    return result.value;\n  } finally {\n    await rm(workspace, { recursive: true, force: true });\n  }\n}\n\n/**\n * Above this many per-file `--allow-fs-read` flags, collapse the staged source\n * files to their common ancestor directory. A large project would\n * otherwise blow the OS argument limit (E2BIG) and the tool could not spawn at\n * all. The collapse is safe here: `sourceFiles` are paths inside the per-run\n * STAGED COPY, which already contains only the reachable source graph — never\n * the real project root with its .env and credentials.\n */\nconst SANDBOX_FS_READ_FLAG_THRESHOLD = 1024;\n\nfunction commonAncestorDir(paths: readonly string[]): string {\n  const dirs = paths.map((path) => resolve(dirname(path)));","sourceCodeStart":4848,"sourceCodeEnd":4884,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/agent/src/runtime.ts#L4848-L4884","documentation":"The sandboxed tool worker answered with a result frame { ok: false } carrying no structured code, so the executor throws the generic fallback (result.code ?? 'cave_sandbox_tool_failed'). Something inside the worker failed - the tool threw a plain unstructured error, the worker process died, or the call was aborted by the timeout/parent signal - and no specific code survived the fd 3 length-prefixed result frame.","triggerScenarios":"Tool code throwing a plain Error (no cave_ code) inside the sandbox worker; worker killed by AbortSignal.timeout(timeoutMs) or the parent signal (combined.aborted); worker crash (OOM, import failure of the entry module); malformed/truncated result frame from the worker.","commonSituations":"Long-running tools hitting a tight timeoutMs; tool entry modules that fail to import inside the sandbox (missing staged dependency); errors from third-party libraries bubbling unstructured; OOM on large inputs.","solutions":["Reproduce the tool outside the sandbox with the same params to see the underlying error","Raise timeoutMs if the abort path is the cause","Make the tool throw errors that carry a machine-readable code so result.code is present and specific","Validate params before dispatch and check the tool's staged entry/dependency graph imports cleanly"],"exampleFix":"// before: tool throws a plain error -> generic code\nrun: async (params) => { throw new Error('boom'); }\n\n// after: throw with a code the worker frame preserves\nrun: async (params) => { const e = new Error('boom'); (e as any).code = 'my_tool_parse_failed'; throw e; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await runSandboxedTool(params);\n} catch (error) {\n  if (error instanceof Error && error.message === 'cave_sandbox_tool_failed') {\n    // generic worker failure: reproduce outside the sandbox to get the real error\n    const real = await reproduceUnsandboxed(params);\n    throw new Error(`sandboxed tool failed; unsandboxed repro says: ${real?.message ?? 'unknown'}`);\n  }\n  throw error;\n}","preventionTips":["Throw errors that carry a machine-readable code from tool code so result.code is specific, not the fallback","Set timeoutMs comfortably above the tool's worst-case runtime","Verify the tool entry and its staged dependency graph import cleanly inside the sandbox","Validate params before dispatch; many unstructured tool errors are input validation failures"],"tags":["sandbox","tool-execution","worker","generic-error"],"backgroundTag":"sandboxed-tool-execution-failed","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}