Skip to main content

systemprompt_loader/
error.rs

1//! Error types raised by the loader infrastructure.
2//!
3//! Three thiserror-derived enums cover the public surface:
4//!
5//! - [`ConfigLoadError`] — services-config reading, YAML parsing, include
6//!   resolution, and validation failures.
7//! - [`ConfigWriteError`] — file creation, agent CRUD, and config-file editing
8//!   failures.
9//! - [`ExtensionLoadError`] — manifest discovery and registry lookups.
10//!
11//! All three implement `std::error::Error` and compose with upstream
12//! errors (`std::io::Error`, `serde_yaml::Error`,
13//! `systemprompt_config::ProfileBootstrapError`,
14//! `systemprompt_models::ServicesValidationError`,
15//! `systemprompt_models::ProfileValidationError`) via `#[from]`.
16//!
17//! Copyright (c) systemprompt.io — Business Source License 1.1.
18//! See <https://systemprompt.io> for licensing details.
19
20use std::path::PathBuf;
21use thiserror::Error;
22
23#[derive(Debug, Error)]
24pub enum ConfigLoadError {
25    #[error("profile bootstrap unavailable: {0}")]
26    ProfileBootstrap(#[from] systemprompt_config::ProfileBootstrapError),
27
28    #[error("io error at {path}: {source}")]
29    Io {
30        path: PathBuf,
31        #[source]
32        source: std::io::Error,
33    },
34
35    #[error("yaml parse failure at {path}: {source}")]
36    Yaml {
37        path: PathBuf,
38        #[source]
39        source: serde_yaml::Error,
40    },
41
42    #[error(
43        "include file not found: {include}\nReferenced in: {referrer}\nEither create the file or \
44         remove it from the includes list."
45    )]
46    IncludeNotFound { include: PathBuf, referrer: PathBuf },
47
48    #[error("include cycle detected: {chain}")]
49    IncludeCycle { chain: String },
50
51    #[error("duplicate agent definition: {0}")]
52    DuplicateAgent(String),
53
54    #[error("duplicate MCP server definition: {0}")]
55    DuplicateMcpServer(String),
56
57    #[error("duplicate plugin definition: {0}")]
58    DuplicatePlugin(String),
59
60    #[error("duplicate marketplace definition: {0}")]
61    DuplicateMarketplace(String),
62
63    #[error("duplicate skill definition: {0}")]
64    DuplicateSkill(String),
65
66    #[error("duplicate external agent definition: {0}")]
67    DuplicateExternalAgent(String),
68
69    #[error("duplicate Slack app definition: {0}")]
70    DuplicateSlackApp(String),
71
72    #[error("duplicate Teams app definition: {0}")]
73    DuplicateTeamsApp(String),
74
75    #[error("duplicate provider definition across services includes: {0}")]
76    DuplicateProvider(String),
77
78    #[error(
79        "Services config not initialized. Call ServicesBootstrap::init() after \
80         ProfileBootstrap::init()"
81    )]
82    NotInitialized,
83
84    #[error("Services config already initialized")]
85    AlreadyInitialized,
86
87    #[error("services config validation failed: {0}")]
88    Validation(String),
89
90    #[error(
91        "include {path} sets `settings:` — settings are only valid in the root config file. Move \
92         the values to the root or remove them from the include."
93    )]
94    IncludeMustNotSetGlobalSettings { path: PathBuf },
95}
96
97#[derive(Debug, Error)]
98pub enum ConfigWriteError {
99    #[error("io error at {path}: {source}")]
100    Io {
101        path: PathBuf,
102        #[source]
103        source: std::io::Error,
104    },
105
106    #[error("yaml serialisation failed: {0}")]
107    YamlEncode(#[from] serde_yaml::Error),
108
109    #[error("Agent file already exists: {0}. Use 'agents edit' to modify.")]
110    AgentFileExists(PathBuf),
111
112    #[error("Agent '{0}' not found in any configuration file")]
113    AgentNotFound(String),
114}
115
116#[derive(Debug, Error)]
117pub enum ExtensionLoadError {
118    #[error("Binary '{name}' not found at {path}")]
119    BinaryNotFound { name: String, path: PathBuf },
120
121    #[error("No manifest.yaml found for extension '{0}' in extensions/")]
122    ManifestMissing(String),
123}
124
125#[derive(Debug, Error)]
126pub enum ProfileLoadError {
127    #[error("io error at {path}: {source}")]
128    Io {
129        path: PathBuf,
130        #[source]
131        source: std::io::Error,
132    },
133
134    #[error(transparent)]
135    Profile(#[from] systemprompt_models::profile::ProfileError),
136}
137
138pub type ConfigLoadResult<T> = Result<T, ConfigLoadError>;
139
140pub type ConfigWriteResult<T> = Result<T, ConfigWriteError>;
141
142pub type ExtensionLoadResult<T> = Result<T, ExtensionLoadError>;
143
144pub type ProfileLoadResult<T> = Result<T, ProfileLoadError>;