1use thiserror::Error;
4
5#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum SandboxError {
9 #[error("code validation failed: {reason}")]
11 ValidationFailed {
12 reason: String,
14 },
15
16 #[error("code exceeds maximum size of {max} bytes (got {actual})")]
18 CodeTooLarge {
19 max: usize,
21 actual: usize,
23 },
24
25 #[error("output exceeds maximum size of {max} bytes")]
27 OutputTooLarge {
28 max: usize,
30 },
31
32 #[error("execution timed out after {timeout_ms}ms")]
34 Timeout {
35 timeout_ms: u64,
37 },
38
39 #[error("banned pattern detected: `{pattern}` — the sandbox has no filesystem, network, or module access. Use forge.callTool() or forge.server() to interact with external services.")]
41 BannedPattern {
42 pattern: String,
44 },
45
46 #[error("sandbox execution failed: {0}")]
48 Execution(#[from] anyhow::Error),
49
50 #[error("javascript error: {message}")]
52 JsError {
53 message: String,
55 },
56
57 #[error("result serialization failed: {0}")]
59 Serialization(#[from] serde_json::Error),
60
61 #[error("concurrency limit reached (max {max} concurrent executions)")]
63 ConcurrencyLimit {
64 max: usize,
66 },
67
68 #[error("tool call limit exceeded (max {max} calls per execution)")]
70 ToolCallLimit {
71 max: usize,
73 },
74
75 #[error("tool call arguments too large (max {max} bytes, got {actual})")]
77 ToolCallArgsTooLarge {
78 max: usize,
80 actual: usize,
82 },
83
84 #[error("V8 heap limit exceeded")]
86 HeapLimitExceeded,
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::executor::ExecutionMode;
93 use crate::ipc::ErrorKind;
94
95 #[test]
98 #[allow(unreachable_patterns)]
99 fn ne_sandbox_enums_are_non_exhaustive() {
100 let err = SandboxError::HeapLimitExceeded;
101 match err {
102 SandboxError::HeapLimitExceeded
103 | SandboxError::Timeout { .. }
104 | SandboxError::ValidationFailed { .. } => {}
105 _ => {}
106 }
107
108 let mode = ExecutionMode::InProcess;
109 match mode {
110 ExecutionMode::InProcess | ExecutionMode::ChildProcess => {}
111 _ => {}
112 }
113
114 let kind = ErrorKind::Timeout;
115 match kind {
116 ErrorKind::Timeout | ErrorKind::HeapLimit | ErrorKind::JsError => {}
117 _ => {}
118 }
119 }
120}