Skip to main content

capsule_runtime/
errors.rs

1use std::path::PathBuf;
2
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum RuntimeError {
7    #[error("artifact {name}@{version} not found in registry")]
8    ArtifactNotFound { name: String, version: String },
9
10    #[error("artifact integrity check failed for {name}@{version}")]
11    ArtifactIntegrityFailed { name: String, version: String },
12
13    #[error("lockfile missing artifact entry for '{name}'")]
14    LockMissingEntry { name: String },
15
16    #[error(
17        "lockfile version mismatch for '{name}': manifest requested {requested}, lock pinned {pinned}"
18    )]
19    LockVersionMismatch {
20        name: String,
21        requested: String,
22        pinned: String,
23    },
24
25    #[error("failed to read artifact archive for {name}@{version}: {message}")]
26    ArtifactArchive {
27        name: String,
28        version: String,
29        message: String,
30    },
31
32    #[error("failed to compile component for {name}@{version}: {message}")]
33    ToolComponentCompile {
34        name: String,
35        version: String,
36        message: String,
37    },
38
39    #[error("failed to compile capsule component: {0}")]
40    CapsuleCompile(String),
41
42    #[error("failed to create workdir at {path}: {source}")]
43    CreateWorkdir {
44        path: String,
45        #[source]
46        source: std::io::Error,
47    },
48
49    #[error("failed to write tool manifest at {path}: {source}")]
50    WriteToolManifest {
51        path: String,
52        #[source]
53        source: std::io::Error,
54    },
55
56    #[error("failed to read inference.system_prompt_file at {path}: {source}")]
57    SystemPromptFileRead {
58        path: String,
59        #[source]
60        source: std::io::Error,
61    },
62
63    #[error(
64        "inference.system_prompt_artifact '{name}': skill.md not found or unreadable; \
65         ensure the skill is declared in artifacts: and the capsule was staged"
66    )]
67    SystemPromptArtifactRead {
68        name: String,
69        #[source]
70        source: std::io::Error,
71    },
72
73    #[error("skill source path not found: {path}")]
74    SkillSourceNotFound { path: String },
75
76    #[error("skill source directory '{path}' contains no skill.md")]
77    SkillSourceMissingSkillMd { path: String },
78
79    #[error("failed to read skill source at {path}: {source}")]
80    SkillSourceRead {
81        path: String,
82        #[source]
83        source: std::io::Error,
84    },
85
86    #[error("invalid network capability allow entry '{entry}': {message}")]
87    InvalidNetworkAllowEntry { entry: String, message: String },
88
89    #[error("invalid filesystem capability scope '{scope}': {message}")]
90    InvalidFilesystemScope { scope: String, message: String },
91
92    #[error(
93        "capsule component missing export murmur:capsule/run@0.1.0#run; rebuild the artifact against the versioned WIT (run `mur install` for a default artifact, or rebuild from source otherwise)"
94    )]
95    CapsuleExportMissing,
96
97    #[error(
98        "tool component '{name}' missing export murmur:tool/run@0.1.0#run; rebuild the artifact against the versioned WIT (run `mur install` for a default artifact, or rebuild from source otherwise)"
99    )]
100    ToolExportMissing { name: String },
101
102    #[error("capsule execution trapped: {0}")]
103    CapsuleTrap(String),
104
105    #[error(
106        "capsule execution exceeded its {seconds}s deadline and was interrupted; \
107         raise capabilities.limits.deadline_seconds in murmur.yaml if the capsule \
108         legitimately needs longer"
109    )]
110    CapsuleDeadlineExceeded { seconds: u64 },
111
112    #[error("capsule execution exceeded its configured resource limits: {message}")]
113    CapsuleResourceLimit { message: String },
114
115    #[error("failed to initialize WASI for {path}: {message}")]
116    WasiInit { path: String, message: String },
117
118    #[error("inference driver is not configured; add inference.driver.artifact to murmur.yaml")]
119    DriverNotConfigured,
120
121    #[error("inference driver '{0}' is not installed in the local tool registry")]
122    DriverNotInstalled(String),
123
124    #[error("agent loop failed: {0}")]
125    AgentLoopFailed(String),
126
127    #[error("internal_port {port} is already bound; choose another port or omit internal_port to use an OS-assigned port")]
128    PortInUse { port: u16 },
129
130    #[error("runtime failure: {0}")]
131    Runtime(String),
132}
133
134impl RuntimeError {
135    #[must_use]
136    pub fn artifact_not_found(name: impl Into<String>, version: impl Into<String>) -> Self {
137        Self::ArtifactNotFound {
138            name: name.into(),
139            version: version.into(),
140        }
141    }
142
143    #[must_use]
144    pub fn artifact_integrity_failed(name: impl Into<String>, version: impl Into<String>) -> Self {
145        Self::ArtifactIntegrityFailed {
146            name: name.into(),
147            version: version.into(),
148        }
149    }
150
151    #[must_use]
152    pub fn wasi(path: PathBuf, message: impl Into<String>) -> Self {
153        Self::WasiInit {
154            path: path.display().to_string(),
155            message: message.into(),
156        }
157    }
158}