Skip to main content

apollo_configuration/
errors.rs

1use apollo_errors::Error;
2use miette::Diagnostic;
3use miette::SourceSpan;
4use std::sync::Arc;
5
6#[derive(Debug, Diagnostic, Error)]
7#[diagnostic()]
8pub(crate) enum ExpandErrorKind {
9    #[error("environment variable not present")]
10    #[diagnostic(code(apollo::configuration::env_missing))]
11    NotPresent {
12        #[label("environment variable not present")]
13        span: SourceSpan,
14    },
15    #[error("invalid expansion kind")]
16    #[diagnostic(code(apollo::configuration::env_invalid))]
17    #[diagnostic(help("only `env.` expansions are supported"))]
18    InvalidExpansion {
19        #[label("invalid expansion kind")]
20        span: SourceSpan,
21    },
22    #[error("expanded value contains invalid characters")]
23    #[diagnostic(code(apollo::configuration::env_invalid))]
24    #[diagnostic(help(
25        "environment variables must contain UTF-8 values to be used in configuration"
26    ))]
27    NotUnicode {
28        #[label("could not expand this value")]
29        span: SourceSpan,
30    },
31    #[error("invalid bare expansion")]
32    #[diagnostic(code(apollo::configuration::env_invalid))]
33    UnprefixedExpansion {
34        #[label("change this to `${{env.{name}}}`")]
35        span: SourceSpan,
36        name: String,
37    },
38}
39
40#[derive(Debug, Diagnostic, Error)]
41#[error("could not expand configuration values")]
42#[diagnostic(code(apollo::configuration::expansion))]
43pub struct ExpandError {
44    // fields are pub(crate) so we can construct these
45    // and inspect the fields in unit tests
46    #[source_code]
47    pub(crate) source_code: Arc<str>,
48    #[related]
49    pub(crate) errors: Vec<ExpandErrorKind>,
50}
51
52/// A JSON schema validation error.
53#[derive(Debug, Error, Diagnostic)]
54#[error("{message}")]
55#[diagnostic(code(apollo::configuration::validation))]
56pub struct ValidationError {
57    #[label("{message}")]
58    pub(crate) label: SourceSpan,
59    pub(crate) message: String,
60}
61
62/// A list of JSON schema validation errors.
63#[derive(Debug, Error, Diagnostic)]
64#[error("schema validation error")]
65#[diagnostic(code(apollo::configuration::schema))]
66pub struct ValidationErrors {
67    #[source_code]
68    pub(crate) source_code: Arc<str>,
69    #[related]
70    pub(crate) errors: Vec<Box<dyn Diagnostic + Send + Sync + 'static>>,
71}
72
73/// Errors that can occur when transforming the YAML input to a JSON-compatible value.
74///
75/// Not all values that YAML can represent are supported in apollo-configuration.
76#[derive(Debug, Error, Diagnostic)]
77pub enum YamlToJsonError {
78    /// Error raised when NaN/Infinity are used in YAML values.
79    ///
80    /// NaN/Infinity are supported in YAML, but not in JSON schema. apollo-configuration rejects those
81    /// values.
82    #[error("unsupported value")]
83    #[diagnostic(code(apollo::configuration::invalid_number))]
84    InvalidNumberError {
85        #[source_code]
86        source_code: Arc<str>,
87        #[label("NaN/Infinity are not suported in configuration")]
88        label: SourceSpan,
89    },
90
91    /// Error raised when an object with non-string keys appears in a YAML value.
92    ///
93    /// YAML supports any type of key value in mappings, but JSON schema does not. apollo-configuration
94    /// rejects such values.
95    #[error("unsupported key")]
96    #[diagnostic(code(apollo::configuration::invalid_mapping))]
97    InvalidMappingError {
98        #[source_code]
99        source_code: Arc<str>,
100        #[label("non-string mapping keys are not supported in configuration")]
101        label: SourceSpan,
102    },
103}
104
105/// Top-level error type.
106#[derive(Debug, Error, Diagnostic)]
107#[non_exhaustive]
108pub enum ConfigError {
109    #[error("{error}")]
110    #[diagnostic(code(apollo::configuration::parse))]
111    ParseError {
112        #[from]
113        error: serde_yaml::Error,
114    },
115
116    #[error("{error}")]
117    #[diagnostic(code(apollo::configuration::parse))]
118    // TODO: Split this between parse error and JsonConversionError?
119    ParseError2 {
120        #[from]
121        error: saphyr::ScanError,
122    },
123
124    // XXX(@goto-bus-stop): I don't love the way this looks in CLI error reports. There is a
125    // tension between providing useful enough context in the main message in text formats like
126    // JSON, and putting information in the most relevant place in CLI diagnostics.
127    #[error("failed to parse value: {error}")]
128    #[diagnostic(code(apollo::configuration::parse))]
129    InvalidValue {
130        #[source_code]
131        source_code: Arc<str>,
132        #[label("this value could not be parsed")]
133        label: Option<SourceSpan>,
134        // XXX(@goto-bus-stop): this should really be annotated with `#[source]`, but then it
135        // looks a bit crap in CLI error reports!
136        error: serde_json::Error,
137    },
138
139    #[error(transparent)]
140    #[diagnostic(transparent)]
141    ValidationError(#[from] ValidationErrors),
142
143    #[error(transparent)]
144    #[diagnostic(transparent)]
145    JsonConversionError(#[from] YamlToJsonError),
146
147    #[error(transparent)]
148    #[diagnostic(transparent)]
149    ExpansionError(#[from] ExpandError),
150}