systemprompt_config/
error.rs1use std::path::PathBuf;
18
19use systemprompt_models::errors::SecretsError;
20use systemprompt_models::profile::ProfileError;
21
22use crate::bootstrap::{ProfileBootstrapError, SecretsBootstrapError};
23use crate::services::ConfigValidationError;
24
25pub type ConfigResult<T> = Result<T, ConfigError>;
26
27#[derive(Debug, thiserror::Error)]
28#[non_exhaustive]
29pub enum ConfigError {
30 #[error("Config already initialized")]
31 AlreadyInitialized,
32
33 #[error(
34 "cannot resolve a stable instance id for a cloud profile: set server.instance_id or \
35 export HOSTNAME so this replica keeps one identity across restarts"
36 )]
37 InstanceIdUnresolved,
38
39 #[error(transparent)]
40 Profile(#[from] ProfileBootstrapError),
41
42 #[error(transparent)]
43 Secrets(#[from] SecretsBootstrapError),
44
45 #[error(transparent)]
46 ProfileParse(#[from] ProfileError),
47
48 #[error(transparent)]
49 SchemaValidation(#[from] ConfigValidationError),
50
51 #[error(transparent)]
52 SecretsParse(#[from] SecretsError),
53
54 #[error(transparent)]
55 Io(#[from] std::io::Error),
56
57 #[error(transparent)]
58 Json(#[from] serde_json::Error),
59
60 #[error(transparent)]
61 Yaml(#[from] serde_yaml::Error),
62
63 #[error("Missing required path: paths.{field}")]
64 MissingProfilePath { field: String },
65
66 #[error("Failed to canonicalize {name} path: {source}")]
67 CanonicalizePath {
68 name: String,
69 #[source]
70 source: std::io::Error,
71 },
72
73 #[error("Profile path '{field}' cannot be read: {path}")]
74 ReadProfilePath {
75 field: String,
76 path: PathBuf,
77 #[source]
78 source: std::io::Error,
79 },
80
81 #[error("Profile path '{field}' has invalid YAML: {path}")]
82 InvalidProfileYaml {
83 field: String,
84 path: PathBuf,
85 #[source]
86 source: serde_yaml::Error,
87 },
88
89 #[error("Profile path validation failed: {message}")]
90 ProfilePathReport { message: String },
91
92 #[error("Unsupported database type '{db_type}'. Only 'postgres' is supported.")]
93 UnsupportedDatabaseType { db_type: String },
94
95 #[error("Invalid database URL: {message}")]
96 InvalidDatabaseUrl { message: String },
97
98 #[error("Failed to resolve variables after {passes} passes: {unresolved}")]
99 UnresolvedVariables { passes: usize, unresolved: String },
100
101 #[error("{count} validation error(s)")]
102 ValidationErrors { count: usize },
103
104 #[error("Required config file missing: {path}")]
105 EnvironmentConfigMissing { path: PathBuf },
106
107 #[error(
108 "Profile is missing required `system_admin.username` and `SYSTEMPROMPT_SYSTEM_ADMIN` is \
109 not set. The platform refuses to start without an explicit system-admin identity."
110 )]
111 MissingSystemAdmin,
112
113 #[error("No provider named {name}")]
114 ProviderNotFound { name: String },
115
116 #[error("No model with id {id} under provider {provider}")]
117 ModelNotFound { id: String, provider: String },
118
119 #[error("Access token expiry must be positive")]
120 NonPositiveAccessTokenExpiry,
121
122 #[error("Refresh token expiry must be positive")]
123 NonPositiveRefreshTokenExpiry,
124
125 #[error("No trusted issuer found with issuer {issuer}")]
126 TrustedIssuerNotFound { issuer: String },
127
128 #[error("{message}")]
129 Other { message: String },
130}
131
132impl ConfigError {
133 pub fn other(message: impl Into<String>) -> Self {
134 Self::Other {
135 message: message.into(),
136 }
137 }
138}