1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Error types for microsandbox.
//--------------------------------------------------------------------------------------------------
// Types
//--------------------------------------------------------------------------------------------------
/// The result type for microsandbox operations.
pub type MicrosandboxResult<T> = Result<T, MicrosandboxError>;
/// Errors that can occur in microsandbox operations.
#[derive(Debug, thiserror::Error)]
pub enum MicrosandboxError {
/// An I/O error occurred.
#[error("io error: {0}")]
Io(#[from] std::io::Error),
/// An HTTP request error occurred.
#[error("http error: {0}")]
Http(#[from] reqwest::Error),
/// The libkrunfw library was not found at the expected location.
#[error("libkrunfw not found: {0}")]
LibkrunfwNotFound(String),
/// A database error occurred.
#[error("database error: {0}")]
Database(#[from] sea_orm::DbErr),
/// Invalid configuration.
#[error("invalid config: {0}")]
InvalidConfig(String),
/// The requested sandbox was not found.
#[error("sandbox not found: {0}")]
SandboxNotFound(String),
/// A sandbox with the given name already exists. Returned by
/// `Sandbox::create` when the name is taken and `replace_existing`
/// was not set, and by `Sandbox::create` with `replace_existing`
/// when an in-process `Sandbox` handle for that name is still
/// alive (the caller must drop or stop the existing handle first).
#[error("sandbox already exists: {0}")]
SandboxAlreadyExists(String),
/// The sandbox is still running and cannot be removed.
#[error("sandbox still running: {0}")]
SandboxStillRunning(String),
/// A runtime error occurred.
#[error("runtime error: {0}")]
Runtime(String),
/// The sandbox process exited before the agent relay became
/// available. Carries the sandbox name and the structured
/// `boot-error.json` record so the CLI can render a useful inline
/// error with hints.
#[error("failed to start {name:?}: {}", .err.message)]
BootStart {
/// The name of the sandbox that failed to start.
name: String,
/// Structured failure record loaded from `boot-error.json`.
err: microsandbox_runtime::boot_error::BootError,
},
/// A JSON serialization/deserialization error occurred.
#[error("json error: {0}")]
Json(#[from] serde_json::Error),
/// A protocol error occurred.
#[error("protocol error: {0}")]
Protocol(#[from] microsandbox_protocol::ProtocolError),
/// A nix/errno error occurred.
#[error("nix error: {0}")]
Nix(#[from] nix::errno::Errno),
/// Command execution timed out.
#[error("exec timed out after {0:?}")]
ExecTimeout(std::time::Duration),
/// A command failed to spawn (binary not found, permission
/// denied, etc.). Distinct from a non-zero exit status: the
/// user code never ran. The CLI renders this as a styled
/// error block with hints; SDK consumers can branch on
/// [`microsandbox_protocol::exec::ExecFailureKind`].
#[error("exec failed: {}", .0.message)]
ExecFailed(microsandbox_protocol::exec::ExecFailed),
/// A terminal operation failed.
#[error("terminal error: {0}")]
Terminal(String),
/// A filesystem operation failed inside the sandbox.
#[error("sandbox fs error: {0}")]
SandboxFs(String),
/// The requested image was not found.
#[error("image not found: {0}")]
ImageNotFound(String),
/// The image is in use by one or more sandboxes.
#[error("image in use by sandbox(es): {0}")]
ImageInUse(String),
/// The requested volume was not found.
#[error("volume not found: {0}")]
VolumeNotFound(String),
/// The volume already exists.
#[error("volume already exists: {0}")]
VolumeAlreadyExists(String),
/// An OCI image operation failed.
#[error("image error: {0}")]
Image(#[from] microsandbox_image::ImageError),
/// A network builder accumulated a parse / validation error.
/// Surfaces from `NetworkBuilder::build()` (and its nested
/// `DnsBuilder::build()`) when chained inside
/// `SandboxBuilder::network(|n| ...)`.
#[cfg(feature = "net")]
#[error("network builder: {0}")]
NetworkBuilder(#[from] microsandbox_network::policy::BuildError),
/// A rootfs patch operation failed.
#[error("patch failed: {0}")]
PatchFailed(String),
/// A snapshot artifact was not found.
#[error("snapshot not found: {0}")]
SnapshotNotFound(String),
/// A snapshot artifact already exists at the given path.
#[error("snapshot already exists: {0}")]
SnapshotAlreadyExists(String),
/// Snapshotting requires the source sandbox to be stopped.
#[error("snapshot source sandbox '{0}' is not stopped")]
SnapshotSandboxRunning(String),
/// The image referenced by a snapshot is not in the local cache.
#[error("snapshot image missing from cache: {0}")]
SnapshotImageMissing(String),
/// The snapshot artifact failed integrity verification.
#[error("snapshot integrity check failed: {0}")]
SnapshotIntegrity(String),
/// Metrics sampling is disabled for this sandbox.
#[error("metrics disabled for sandbox: {0}")]
MetricsDisabled(String),
/// A custom error message.
#[error("{0}")]
Custom(String),
}
impl microsandbox_db::retry::IsSqliteBusy for MicrosandboxError {
fn is_sqlite_busy(&self) -> bool {
matches!(self, MicrosandboxError::Database(db_err) if microsandbox_db::retry::is_sqlite_busy(db_err))
}
}