Skip to main content

devboy_skills/
error.rs

1//! Error types for the skills subsystem.
2
3use std::path::PathBuf;
4
5/// Result alias used throughout `devboy-skills`.
6pub type Result<T> = std::result::Result<T, SkillError>;
7
8/// Errors that can surface while loading, parsing, or installing a skill.
9#[derive(Debug, thiserror::Error)]
10pub enum SkillError {
11    /// The skill body did not open with a YAML frontmatter block
12    /// (`---` at line 1, closing `---` on a subsequent line).
13    #[error("skill `{skill}`: missing YAML frontmatter delimiter `---`")]
14    MissingFrontmatter {
15        /// Identifier of the offending skill (directory name).
16        skill: String,
17    },
18
19    /// The YAML frontmatter parsed but did not contain a required field.
20    #[error("skill `{skill}`: required frontmatter field `{field}` is missing")]
21    MissingRequiredField {
22        /// Identifier of the offending skill.
23        skill: String,
24        /// Name of the missing field.
25        field: &'static str,
26    },
27
28    /// The YAML frontmatter parsed but a field had the wrong type.
29    #[error("skill `{skill}`: frontmatter field `{field}` has invalid type ({reason})")]
30    InvalidFieldType {
31        /// Identifier of the offending skill.
32        skill: String,
33        /// Name of the offending field.
34        field: &'static str,
35        /// Why the value is rejected.
36        reason: String,
37    },
38
39    /// The `category` field references a category that is not in the
40    /// known enum. Provide one of the shipped categories (self-bootstrap,
41    /// issue-tracking, code-review, self-feedback, meeting-notes, messenger)
42    /// or extend [`crate::skill::Category`] before shipping a new one.
43    #[error("skill `{skill}`: unknown category `{category}`")]
44    UnknownCategory {
45        /// Identifier of the offending skill.
46        skill: String,
47        /// The string that failed to parse as a category.
48        category: String,
49    },
50
51    /// Underlying YAML parser failure (syntax error inside the frontmatter).
52    #[error("skill `{skill}`: invalid YAML in frontmatter: {source}")]
53    InvalidYaml {
54        /// Identifier of the offending skill.
55        skill: String,
56        /// Wrapped YAML error.
57        #[source]
58        source: serde_yaml::Error,
59    },
60
61    /// A skill lookup was asked for a name that the source does not know
62    /// about.
63    #[error("skill `{name}` not found in source `{source_name}`")]
64    NotFound {
65        /// Name that was requested.
66        name: String,
67        /// The source that was queried.
68        source_name: &'static str,
69    },
70
71    /// Filesystem operation failed while reading or writing a skill / manifest.
72    #[error("filesystem error at `{path}`: {source}")]
73    Io {
74        /// Path that was being accessed.
75        path: PathBuf,
76        /// Wrapped IO error.
77        #[source]
78        source: std::io::Error,
79    },
80
81    /// Manifest JSON parse failure.
82    #[error("manifest at `{path}`: invalid JSON ({source})")]
83    InvalidManifest {
84        /// Path to the offending manifest.
85        path: PathBuf,
86        /// Wrapped serde_json error.
87        #[source]
88        source: serde_json::Error,
89    },
90
91    /// Non-manifest JSON (de)serialisation failure — used by the trace
92    /// subsystem for `trace.jsonl` records and `meta.json` writes so
93    /// callers do not see a misleading "manifest … invalid JSON"
94    /// error for a record that is not a manifest.
95    #[error("failed to {operation} JSON at `{path}`: {source}")]
96    SerdeJson {
97        /// What was being done when the failure happened
98        /// (`serialise trace record`, `write session meta`, …).
99        operation: &'static str,
100        /// Path associated with the record.
101        path: PathBuf,
102        /// Wrapped serde_json error.
103        #[source]
104        source: serde_json::Error,
105    },
106}