Skip to main content

adk_sandbox/
error.rs

1//! Error types for sandbox execution.
2
3use std::time::Duration;
4use thiserror::Error;
5
6/// Errors that can occur during sandbox execution.
7///
8/// All variants include actionable context to help callers diagnose issues.
9///
10/// # Example
11///
12/// ```rust
13/// use adk_sandbox::SandboxError;
14/// use std::time::Duration;
15///
16/// let err = SandboxError::Timeout { timeout: Duration::from_secs(30) };
17/// assert!(err.to_string().contains("30s"));
18/// ```
19#[derive(Debug, Clone, Error)]
20pub enum SandboxError {
21    /// Execution exceeded the configured timeout.
22    #[error("execution timed out after {timeout:?}")]
23    Timeout {
24        /// The timeout duration that was exceeded.
25        timeout: Duration,
26    },
27
28    /// Execution exceeded the configured memory limit (Wasm only).
29    #[error("memory limit exceeded: {limit_mb} MB")]
30    MemoryExceeded {
31        /// The memory limit in megabytes that was exceeded.
32        limit_mb: u32,
33    },
34
35    /// Execution failed due to an internal error (e.g., subprocess I/O failure).
36    #[error("execution failed: {0}")]
37    ExecutionFailed(String),
38
39    /// The request is invalid (e.g., unsupported language for this backend).
40    #[error("invalid request: {0}")]
41    InvalidRequest(String),
42
43    /// The backend is not available (e.g., missing runtime or feature not enabled).
44    #[error("backend unavailable: {0}")]
45    BackendUnavailable(String),
46
47    /// The sandbox enforcer failed to apply the profile.
48    #[error("enforcer '{enforcer}' failed: {message}")]
49    EnforcerFailed {
50        /// The enforcer name (e.g., "seatbelt", "bubblewrap", "appcontainer").
51        enforcer: String,
52        /// A descriptive message explaining what failed.
53        message: String,
54    },
55
56    /// The sandbox enforcer is not available on this system.
57    #[error("enforcer '{enforcer}' unavailable: {message}")]
58    EnforcerUnavailable {
59        /// The enforcer name.
60        enforcer: String,
61        /// A message explaining why the enforcer is not functional.
62        message: String,
63    },
64
65    /// A policy path or resource could not be resolved.
66    #[error("policy violation: {0}")]
67    PolicyViolation(String),
68}
69
70impl From<std::io::Error> for SandboxError {
71    fn from(err: std::io::Error) -> Self {
72        SandboxError::ExecutionFailed(format!("I/O error: {err}"))
73    }
74}
75
76impl From<SandboxError> for adk_core::AdkError {
77    fn from(err: SandboxError) -> Self {
78        use adk_core::{ErrorCategory, ErrorComponent};
79        let (category, code) = match &err {
80            SandboxError::Timeout { .. } => (ErrorCategory::Timeout, "code.sandbox_timeout"),
81            SandboxError::MemoryExceeded { .. } => (ErrorCategory::Internal, "code.sandbox_memory"),
82            SandboxError::ExecutionFailed(_) => (ErrorCategory::Internal, "code.sandbox_execution"),
83            SandboxError::InvalidRequest(_) => {
84                (ErrorCategory::InvalidInput, "code.sandbox_invalid_request")
85            }
86            SandboxError::BackendUnavailable(_) => {
87                (ErrorCategory::Unavailable, "code.sandbox_unavailable")
88            }
89            SandboxError::EnforcerFailed { .. } => {
90                (ErrorCategory::Internal, "code.sandbox_enforcer_failed")
91            }
92            SandboxError::EnforcerUnavailable { .. } => {
93                (ErrorCategory::Unavailable, "code.sandbox_enforcer_unavailable")
94            }
95            SandboxError::PolicyViolation(_) => {
96                (ErrorCategory::InvalidInput, "code.sandbox_policy_violation")
97            }
98        };
99        adk_core::AdkError::new(ErrorComponent::Code, category, code, err.to_string())
100            .with_source(err)
101    }
102}