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
use std::path::PathBuf;
/// Errors that occur while loading or validating FraiseQL configuration.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ConfigError {
/// No configuration file was found at the expected location(s).
#[error("Configuration file not found")]
NotFound,
/// The configuration file was found but could not be read from disk.
#[error("Failed to read configuration file {path}: {source}")]
ReadError {
/// Path to the file that could not be read.
path: PathBuf,
/// Underlying I/O error.
source: std::io::Error,
},
/// The configuration file was read successfully but contains invalid TOML
/// or does not conform to the expected schema.
#[error("Failed to parse configuration: {source}")]
ParseError {
/// The TOML deserialisation error.
#[from]
source: toml::de::Error,
},
/// A configuration value failed a semantic validation rule (e.g. a port
/// number that is out of range, or conflicting options).
#[error("Validation error in {field}: {message}")]
ValidationError {
/// Dot-separated path to the invalid configuration field.
field: String,
/// Human-readable description of why the value is invalid.
message: String,
},
/// A required environment variable was not set at startup.
#[error("Missing required environment variable: {name}")]
MissingEnvVar {
/// Name of the missing environment variable.
name: String,
},
/// Several configuration errors were collected together (e.g. during a
/// full-file validation pass) and are reported as a single error.
#[error("Multiple configuration errors")]
MultipleErrors {
/// All individual errors that were encountered.
errors: Vec<ConfigError>,
},
}
impl ConfigError {
/// Returns a short, stable error code string suitable for API responses and
/// structured logging.
pub const fn error_code(&self) -> &'static str {
match self {
Self::NotFound => "config_not_found",
Self::ReadError { .. } => "config_read_error",
Self::ParseError { .. } => "config_parse_error",
Self::ValidationError { .. } => "config_validation_error",
Self::MissingEnvVar { .. } => "config_missing_env",
Self::MultipleErrors { .. } => "config_multiple_errors",
}
}
}