viceroy_lib/
error.rs

1//! Error types.
2
3use std::error::Error as StdError;
4use std::io;
5use {crate::wiggle_abi::types::FastlyStatus, url::Url, wiggle::GuestError};
6
7#[derive(Debug, thiserror::Error)]
8#[non_exhaustive]
9pub enum Error {
10    /// Thrown by hostcalls when a buffer is larger than its `*_len` limit.
11    #[error("Buffer length error: {buf} too long to fit in {len}")]
12    BufferLengthError {
13        buf: &'static str,
14        len: &'static str,
15    },
16
17    /// Error when viceroy has encountered a fatal error and the underlying wasmtime
18    /// instance must be terminated with a Trap.
19    #[error("Fatal error: [{0}]")]
20    FatalError(String),
21
22    /// Error when viceroy has been given an invalid file.
23    #[error("Expected a valid Wasm file")]
24    FileFormat,
25
26    #[error("Expected a valid wastime's profiling strategy")]
27    ProfilingStrategy,
28
29    #[error(transparent)]
30    FastlyConfig(#[from] FastlyConfigError),
31
32    #[error("Could not determine address from backend URL: {0}")]
33    BackendUrl(Url),
34
35    /// An error from guest-provided arguments to a hostcall. These errors may be created
36    /// automatically by the Wiggle-generated glue code that converts parameters from their ABI
37    /// representation into richer Rust types, or by fallible methods of `GuestPtr` in the
38    /// wiggle_abi trait implementations.
39    #[error("Guest error: [{0}]")]
40    GuestError(#[from] wiggle::GuestError),
41
42    #[error(transparent)]
43    HandleError(#[from] HandleError),
44
45    #[error(transparent)]
46    HyperError(#[from] hyper::Error),
47
48    #[error(transparent)]
49    Infallible(#[from] std::convert::Infallible),
50
51    /// Error when an invalid argument is supplied to a hostcall.
52    #[error("Invalid argument given")]
53    InvalidArgument,
54
55    #[error(transparent)]
56    InvalidHeaderName(#[from] http::header::InvalidHeaderName),
57
58    #[error(transparent)]
59    InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
60
61    #[error(transparent)]
62    InvalidMethod(#[from] http::method::InvalidMethod),
63
64    #[error(transparent)]
65    InvalidStatusCode(#[from] http::status::InvalidStatusCode),
66
67    #[error(transparent)]
68    InvalidUri(#[from] http::uri::InvalidUri),
69
70    #[error(transparent)]
71    IoError(#[from] std::io::Error),
72
73    #[error(transparent)]
74    Other(#[from] anyhow::Error),
75
76    #[error("Unsupported operation: {msg}")]
77    Unsupported { msg: &'static str },
78
79    /// Downstream response is already sending.
80    #[error("Downstream response already sending")]
81    DownstreamRespSending,
82
83    #[error("Unexpected error sending a chunk to a streaming body")]
84    StreamingChunkSend,
85
86    #[error("Unknown backend: {0}")]
87    UnknownBackend(String),
88
89    #[error(transparent)]
90    DictionaryError(#[from] crate::wiggle_abi::DictionaryError),
91
92    #[error(transparent)]
93    DeviceDetectionError(#[from] crate::wiggle_abi::DeviceDetectionError),
94
95    #[error(transparent)]
96    ObjectStoreError(#[from] crate::object_store::ObjectStoreError),
97
98    #[error(transparent)]
99    KvStoreError(#[from] crate::object_store::KvStoreError),
100
101    #[error(transparent)]
102    SecretStoreError(#[from] crate::wiggle_abi::SecretStoreError),
103
104    #[error{"Expected UTF-8"}]
105    Utf8Expected(#[from] std::str::Utf8Error),
106
107    #[error{"Unsupported ABI version"}]
108    AbiVersionMismatch,
109
110    #[error(transparent)]
111    DownstreamRequestError(#[from] DownstreamRequestError),
112
113    #[error("{0} is not currently supported for local testing")]
114    NotAvailable(&'static str),
115
116    #[error("Could not load native certificates: {0}")]
117    BadCerts(std::io::Error),
118
119    #[error("Could not generate new backend name from '{0}'")]
120    BackendNameRegistryError(String),
121
122    #[error(transparent)]
123    HttpError(#[from] http::Error),
124
125    #[error("Object Store '{0}' does not exist")]
126    UnknownObjectStore(String),
127
128    #[error("Invalid Object Store `key` value used: {0}.")]
129    ObjectStoreKeyValidationError(#[from] crate::object_store::KeyValidationError),
130
131    #[error("Unfinished streaming body")]
132    UnfinishedStreamingBody,
133
134    #[error("Shared memory not supported yet")]
135    SharedMemory,
136
137    #[error("Value absent from structure")]
138    ValueAbsent,
139
140    #[error("String conversion error")]
141    ToStr(#[from] http::header::ToStrError),
142
143    #[error("invalid client certificate")]
144    InvalidClientCert(#[from] crate::config::ClientCertError),
145
146    #[error("Invalid response to ALPN request; wanted '{0}', got '{1}'")]
147    InvalidAlpnRepsonse(&'static str, String),
148
149    #[error("Resource temporarily unavailable")]
150    Again,
151}
152
153impl Error {
154    /// Convert to an error code representation suitable for passing across the ABI boundary.
155    ///
156    /// For more information about specific error codes see [`fastly_shared::FastlyStatus`][status],
157    /// as well as the `witx` interface definition located in `wasm_abi/typenames.witx`.
158    ///
159    /// [status]: fastly_shared/struct.FastlyStatus.html
160    pub fn to_fastly_status(&self) -> FastlyStatus {
161        match self {
162            Error::BufferLengthError { .. } => FastlyStatus::Buflen,
163            Error::InvalidArgument => FastlyStatus::Inval,
164            Error::ValueAbsent => FastlyStatus::None,
165            Error::Unsupported { .. } | Error::NotAvailable(_) => FastlyStatus::Unsupported,
166            Error::HandleError { .. } => FastlyStatus::Badf,
167            Error::InvalidStatusCode { .. } => FastlyStatus::Inval,
168            Error::UnknownBackend(_) | Error::InvalidClientCert(_) => FastlyStatus::Inval,
169            // Map specific kinds of `hyper::Error` into their respective error codes.
170            Error::HyperError(e) if e.is_parse() => FastlyStatus::Httpinvalid,
171            Error::HyperError(e) if e.is_user() => FastlyStatus::Httpuser,
172            Error::HyperError(e) if e.is_incomplete_message() => FastlyStatus::Httpincomplete,
173            Error::HyperError(e)
174                if e.source()
175                    .and_then(|e| e.downcast_ref::<io::Error>())
176                    .map(|ioe| ioe.kind())
177                    == Some(io::ErrorKind::UnexpectedEof) =>
178            {
179                FastlyStatus::Httpincomplete
180            }
181            Error::HyperError(_) => FastlyStatus::Error,
182            // Destructuring a GuestError is recursive, so we use a helper function:
183            Error::GuestError(e) => Self::guest_error_fastly_status(e),
184            // We delegate to some error types' own implementation of `to_fastly_status`.
185            Error::DictionaryError(e) => e.to_fastly_status(),
186            Error::DeviceDetectionError(e) => e.to_fastly_status(),
187            Error::ObjectStoreError(e) => e.into(),
188            Error::KvStoreError(e) => e.into(),
189            Error::SecretStoreError(e) => e.into(),
190            Error::Again => FastlyStatus::Again,
191            // All other hostcall errors map to a generic `ERROR` value.
192            Error::AbiVersionMismatch
193            | Error::BackendUrl(_)
194            | Error::BadCerts(_)
195            | Error::DownstreamRequestError(_)
196            | Error::DownstreamRespSending
197            | Error::FastlyConfig(_)
198            | Error::FatalError(_)
199            | Error::FileFormat
200            | Error::Infallible(_)
201            | Error::InvalidHeaderName(_)
202            | Error::InvalidHeaderValue(_)
203            | Error::InvalidMethod(_)
204            | Error::InvalidUri(_)
205            | Error::IoError(_)
206            | Error::Other(_)
207            | Error::ProfilingStrategy
208            | Error::StreamingChunkSend
209            | Error::Utf8Expected(_)
210            | Error::BackendNameRegistryError(_)
211            | Error::HttpError(_)
212            | Error::UnknownObjectStore(_)
213            | Error::ObjectStoreKeyValidationError(_)
214            | Error::UnfinishedStreamingBody
215            | Error::SharedMemory
216            | Error::ToStr(_)
217            | Error::InvalidAlpnRepsonse(_, _) => FastlyStatus::Error,
218        }
219    }
220
221    fn guest_error_fastly_status(e: &GuestError) -> FastlyStatus {
222        use GuestError::*;
223        match e {
224            PtrNotAligned { .. } => FastlyStatus::Badalign,
225            // We may want to expand the FastlyStatus enum to distinguish between more of these
226            // values.
227            InvalidFlagValue { .. }
228            | InvalidEnumValue { .. }
229            | PtrOutOfBounds { .. }
230            | PtrBorrowed { .. }
231            | PtrOverflow { .. }
232            | InvalidUtf8 { .. }
233            | TryFromIntError { .. } => FastlyStatus::Inval,
234            // These errors indicate either a pathological user input or an internal programming
235            // error
236            BorrowCheckerOutOfHandles | SliceLengthsDiffer => FastlyStatus::Error,
237            // Recursive case: InFunc wraps a GuestError with some context which
238            // doesn't determine what sort of FastlyStatus we return.
239            InFunc { err, .. } => Self::guest_error_fastly_status(err),
240        }
241    }
242}
243
244/// Errors thrown due to an invalid resource handle of some kind.
245#[derive(Debug, thiserror::Error)]
246pub enum HandleError {
247    /// A request handle was not valid.
248    #[error("Invalid request handle: {0}")]
249    InvalidRequestHandle(crate::wiggle_abi::types::RequestHandle),
250
251    /// A response handle was not valid.
252    #[error("Invalid response handle: {0}")]
253    InvalidResponseHandle(crate::wiggle_abi::types::ResponseHandle),
254
255    /// A body handle was not valid.
256    #[error("Invalid body handle: {0}")]
257    InvalidBodyHandle(crate::wiggle_abi::types::BodyHandle),
258
259    /// A logging endpoint handle was not valid.
260    #[error("Invalid endpoint handle: {0}")]
261    InvalidEndpointHandle(crate::wiggle_abi::types::EndpointHandle),
262
263    /// A request handle was not valid.
264    #[error("Invalid pending request handle: {0}")]
265    InvalidPendingRequestHandle(crate::wiggle_abi::types::PendingRequestHandle),
266
267    /// A lookup handle was not valid.
268    #[error("Invalid pending KV lookup handle: {0}")]
269    InvalidPendingKvLookupHandle(crate::wiggle_abi::types::PendingKvLookupHandle),
270
271    /// A insert handle was not valid.
272    #[error("Invalid pending KV insert handle: {0}")]
273    InvalidPendingKvInsertHandle(crate::wiggle_abi::types::PendingKvInsertHandle),
274
275    /// A delete handle was not valid.
276    #[error("Invalid pending KV delete handle: {0}")]
277    InvalidPendingKvDeleteHandle(crate::wiggle_abi::types::PendingKvDeleteHandle),
278
279    /// A list handle was not valid.
280    #[error("Invalid pending KV list handle: {0}")]
281    InvalidPendingKvListHandle(crate::wiggle_abi::types::PendingKvListHandle),
282
283    /// A dictionary handle was not valid.
284    #[error("Invalid dictionary handle: {0}")]
285    InvalidDictionaryHandle(crate::wiggle_abi::types::DictionaryHandle),
286
287    /// An object-store handle was not valid.
288    #[error("Invalid object-store handle: {0}")]
289    InvalidObjectStoreHandle(crate::wiggle_abi::types::ObjectStoreHandle),
290
291    /// A secret store handle was not valid.
292    #[error("Invalid secret store handle: {0}")]
293    InvalidSecretStoreHandle(crate::wiggle_abi::types::SecretStoreHandle),
294
295    /// A secret handle was not valid.
296    #[error("Invalid secret handle: {0}")]
297    InvalidSecretHandle(crate::wiggle_abi::types::SecretHandle),
298
299    /// An async item handle was not valid.
300    #[error("Invalid async item handle: {0}")]
301    InvalidAsyncItemHandle(crate::wiggle_abi::types::AsyncItemHandle),
302
303    /// An acl handle was not valid.
304    #[error("Invalid acl handle: {0}")]
305    InvalidAclHandle(crate::wiggle_abi::types::AclHandle),
306}
307
308/// Errors that can occur in a worker thread running a guest module.
309///
310/// See [`ExecuteCtx::handle_request`][handle_request] and [`ExecuteCtx::run_guest`][run_guest] for
311/// more information about guest execution.
312///
313/// [handle_request]: ../execute/struct.ExecuteCtx.html#method.handle_request
314/// [run_guest]: ../execute/struct.ExecuteCtx.html#method.run_guest
315#[derive(Debug, thiserror::Error)]
316pub(crate) enum ExecutionError {
317    /// Errors thrown by the guest's entrypoint.
318    ///
319    /// See [`wasmtime::Func::call`][call] for more information.
320    ///
321    /// [call]: https://docs.rs/wasmtime/latest/wasmtime/struct.Func.html#method.call
322    #[error("WebAssembly execution trapped: {0}")]
323    WasmTrap(anyhow::Error),
324
325    /// Errors thrown when trying to instantiate a guest context.
326    #[error("Error creating context: {0}")]
327    Context(anyhow::Error),
328
329    /// Errors thrown when type-checking WebAssembly before instantiation
330    #[error("Error type-checking WebAssembly instantiation: {0}")]
331    Typechecking(anyhow::Error),
332
333    /// Errors thrown when trying to instantiate a guest module.
334    #[error("Error instantiating WebAssembly: {0}")]
335    Instantiation(anyhow::Error),
336}
337
338/// Errors that can occur while parsing a `fastly.toml` file.
339#[derive(Debug, thiserror::Error)]
340pub enum FastlyConfigError {
341    /// An I/O error that occurred while reading the file.
342    #[error("error reading '{path}': {err}")]
343    IoError {
344        path: String,
345        #[source]
346        err: std::io::Error,
347    },
348
349    #[error("invalid configuration for '{name}': {err}")]
350    InvalidDeviceDetectionDefinition {
351        name: String,
352        #[source]
353        err: DeviceDetectionConfigError,
354    },
355
356    #[error("invalid configuration for '{name}': {err}")]
357    InvalidGeolocationDefinition {
358        name: String,
359        #[source]
360        err: GeolocationConfigError,
361    },
362
363    #[error("invalid configuration for '{name}': {err}")]
364    InvalidAclDefinition {
365        name: String,
366        #[source]
367        err: AclConfigError,
368    },
369
370    #[error("invalid configuration for '{name}': {err}")]
371    InvalidBackendDefinition {
372        name: String,
373        #[source]
374        err: BackendConfigError,
375    },
376
377    #[error("invalid configuration for '{name}': {err}")]
378    InvalidDictionaryDefinition {
379        name: String,
380        #[source]
381        err: DictionaryConfigError,
382    },
383
384    #[error("invalid configuration for '{name}': {err}")]
385    InvalidObjectStoreDefinition {
386        name: String,
387        #[source]
388        err: ObjectStoreConfigError,
389    },
390
391    #[error("invalid configuration for '{name}': {err}")]
392    InvalidSecretStoreDefinition {
393        name: String,
394        #[source]
395        err: SecretStoreConfigError,
396    },
397
398    #[error("invalid configuration for '{name}': {err}")]
399    InvalidShieldingSiteDefinition {
400        name: String,
401        #[source]
402        err: ShieldingSiteConfigError,
403    },
404
405    /// An error that occurred while deserializing the file.
406    ///
407    /// This represents errors caused by syntactically invalid TOML data, missing fields, etc.
408    #[error("error parsing `fastly.toml`: {0}")]
409    InvalidFastlyToml(#[from] toml::de::Error),
410
411    /// An error caused by an invalid manifest version.
412    ///
413    /// This means that the provided version is not compliant with the semver spec. See the
414    /// documentation of [`semver::Version::parse`][parse-errors] for more information.
415    ///
416    /// [parse-errors]: https://docs.rs/semver/latest/semver/struct.Version.html#errors
417    #[error("invalid manifest version: {0}")]
418    InvalidManifestVersion(#[from] semver::SemVerError),
419}
420
421/// Errors that may occur while validating acl configurations.
422#[derive(Debug, thiserror::Error)]
423pub enum AclConfigError {
424    /// An I/O error that occurred while processing a file.
425    #[error(transparent)]
426    IoError(std::io::Error),
427
428    /// An error occurred parsing JSON.
429    #[error(transparent)]
430    JsonError(serde_json::error::Error),
431
432    #[error("acl must be a TOML table or string")]
433    InvalidType,
434
435    #[error("missing 'file' field")]
436    MissingFile,
437}
438
439/// Errors that may occur while validating backend configurations.
440#[derive(Debug, thiserror::Error)]
441pub enum BackendConfigError {
442    #[error("definition was not provided as a TOML table")]
443    InvalidEntryType,
444
445    #[error("invalid override_host: {0}")]
446    InvalidOverrideHost(#[from] http::header::InvalidHeaderValue),
447
448    #[error("'override_host' field is empty")]
449    EmptyOverrideHost,
450
451    #[error("'override_host' field was not a string")]
452    InvalidOverrideHostEntry,
453
454    #[error("'cert_host' field is empty")]
455    EmptyCertHost,
456
457    #[error("'cert_host' field was not a string")]
458    InvalidCertHostEntry,
459
460    #[error("'ca_certificate' field is empty")]
461    EmptyCACert,
462
463    #[error("'ca_certificate' field was invalid: {0}")]
464    InvalidCACertEntry(String),
465
466    #[error("'use_sni' field was not a boolean")]
467    InvalidUseSniEntry,
468
469    #[error("'grpc' field was not a boolean")]
470    InvalidGrpcEntry,
471
472    #[error("invalid url: {0}")]
473    InvalidUrl(#[from] http::uri::InvalidUri),
474
475    #[error("'url' field was not a string")]
476    InvalidUrlEntry,
477
478    #[error("no default definition provided")]
479    MissingDefault,
480
481    #[error("missing 'url' field")]
482    MissingUrl,
483
484    #[error("unrecognized key '{0}'")]
485    UnrecognizedKey(String),
486
487    #[error(transparent)]
488    ClientCertError(#[from] crate::config::ClientCertError),
489}
490
491/// Errors that may occur while validating dictionary configurations.
492#[derive(Debug, thiserror::Error)]
493pub enum DictionaryConfigError {
494    /// An I/O error that occurred while reading the file.
495    #[error(transparent)]
496    IoError(std::io::Error),
497
498    #[error("'contents' was not provided as a TOML table")]
499    InvalidContentsType,
500
501    #[error("inline dictionary value was not a string")]
502    InvalidInlineEntryType,
503
504    #[error("definition was not provided as a TOML table")]
505    InvalidEntryType,
506
507    #[error("'name' field was not a string")]
508    InvalidNameEntry,
509
510    #[error("'{0}' is not a valid format for the dictionary. Supported format(s) are: 'inline-toml', 'json'.")]
511    InvalidDictionaryFormat(String),
512
513    #[error("'file' field is empty")]
514    EmptyFileEntry,
515
516    #[error("'format' field is empty")]
517    EmptyFormatEntry,
518
519    #[error("'file' field was not a string")]
520    InvalidFileEntry,
521
522    #[error("'format' field was not a string")]
523    InvalidFormatEntry,
524
525    #[error("missing 'contents' field")]
526    MissingContents,
527
528    #[error("no default definition provided")]
529    MissingDefault,
530
531    #[error("missing 'name' field")]
532    MissingName,
533
534    #[error("missing 'file' field")]
535    MissingFile,
536
537    #[error("missing 'format' field")]
538    MissingFormat,
539
540    #[error("unrecognized key '{0}'")]
541    UnrecognizedKey(String),
542
543    #[error("Item key named '{key}' is too long, max size is {size}")]
544    DictionaryItemKeyTooLong { key: String, size: i32 },
545
546    #[error("too many items, max amount is {size}")]
547    DictionaryCountTooLong { size: i32 },
548
549    #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
550    DictionaryItemValueWrongFormat { key: String },
551
552    #[error("Item value named '{key}' is too long, max size is {size}")]
553    DictionaryItemValueTooLong { key: String, size: i32 },
554
555    #[error(
556        "The file is of the wrong format. The file is expected to contain a single JSON Object"
557    )]
558    DictionaryFileWrongFormat,
559}
560
561/// Errors that may occur while validating device detection configurations.
562#[derive(Debug, thiserror::Error)]
563pub enum DeviceDetectionConfigError {
564    /// An I/O error that occured while reading the file.
565    #[error(transparent)]
566    IoError(std::io::Error),
567
568    #[error("definition was not provided as a TOML table")]
569    InvalidEntryType,
570
571    #[error("missing 'file' field")]
572    MissingFile,
573
574    #[error("'file' field is empty")]
575    EmptyFileEntry,
576
577    #[error("missing 'user_agents' field")]
578    MissingUserAgents,
579
580    #[error("inline device detection value was not a string")]
581    InvalidInlineEntryType,
582
583    #[error("'file' field was not a string")]
584    InvalidFileEntry,
585
586    #[error("'user_agents' was not provided as a TOML table")]
587    InvalidUserAgentsType,
588
589    #[error("unrecognized key '{0}'")]
590    UnrecognizedKey(String),
591
592    #[error("missing 'format' field")]
593    MissingFormat,
594
595    #[error("'format' field was not a string")]
596    InvalidFormatEntry,
597
598    #[error("'{0}' is not a valid format for the device detection mapping. Supported format(s) are: 'inline-toml', 'json'.")]
599    InvalidDeviceDetectionMappingFormat(String),
600
601    #[error(
602        "The file is of the wrong format. The file is expected to contain a single JSON Object"
603    )]
604    DeviceDetectionFileWrongFormat,
605
606    #[error("'format' field is empty")]
607    EmptyFormatEntry,
608
609    #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
610    DeviceDetectionItemValueWrongFormat { key: String },
611}
612
613/// Errors that may occur while validating geolocation configurations.
614#[derive(Debug, thiserror::Error)]
615pub enum GeolocationConfigError {
616    /// An I/O error that occured while reading the file.
617    #[error(transparent)]
618    IoError(std::io::Error),
619
620    #[error("definition was not provided as a TOML table")]
621    InvalidEntryType,
622
623    #[error("missing 'file' field")]
624    MissingFile,
625
626    #[error("'file' field is empty")]
627    EmptyFileEntry,
628
629    #[error("missing 'addresses' field")]
630    MissingAddresses,
631
632    #[error("inline geolocation value was not a string")]
633    InvalidInlineEntryType,
634
635    #[error("'file' field was not a string")]
636    InvalidFileEntry,
637
638    #[error("'addresses' was not provided as a TOML table")]
639    InvalidAddressesType,
640
641    #[error("unrecognized key '{0}'")]
642    UnrecognizedKey(String),
643
644    #[error("missing 'format' field")]
645    MissingFormat,
646
647    #[error("'format' field was not a string")]
648    InvalidFormatEntry,
649
650    #[error("IP address not valid: '{0}'")]
651    InvalidAddressEntry(String),
652
653    #[error("'{0}' is not a valid format for the geolocation mapping. Supported format(s) are: 'inline-toml', 'json'.")]
654    InvalidGeolocationMappingFormat(String),
655
656    #[error(
657        "The file is of the wrong format. The file is expected to contain a single JSON Object"
658    )]
659    GeolocationFileWrongFormat,
660
661    #[error("'format' field is empty")]
662    EmptyFormatEntry,
663
664    #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String")]
665    GeolocationItemValueWrongFormat { key: String },
666}
667
668/// Errors that may occur while validating object store configurations.
669#[derive(Debug, thiserror::Error)]
670pub enum ObjectStoreConfigError {
671    /// An I/O error that occured while reading the file.
672    #[error(transparent)]
673    IoError(std::io::Error),
674    #[error("The `file` and `data` keys for the object `{0}` are set. Only one can be used.")]
675    FileAndData(String),
676    #[error("The `file` or `data` key for the object `{0}` is not set. One must be used.")]
677    NoFileOrData(String),
678    #[error("The `data` value for the object `{0}` is not a string.")]
679    DataNotAString(String),
680    #[error("The `metadata` value for the object `{0}` is not a string.")]
681    MetadataNotAString(String),
682    #[error("The `file` value for the object `{0}` is not a string.")]
683    FileNotAString(String),
684    #[error("The `key` key for an object is not set. It must be used.")]
685    NoKey,
686    #[error("The `key` value for an object is not a string.")]
687    KeyNotAString,
688    #[error("There is no array of objects for the given store.")]
689    NotAnArray,
690    #[error("There is an object in the given store that is not a table of keys.")]
691    NotATable,
692    #[error("There was an error when manipulating the ObjectStore: {0}.")]
693    ObjectStoreError(#[from] crate::object_store::ObjectStoreError),
694    #[error("There was an error when manipulating the KvStore: {0}.")]
695    KvStoreError(#[from] crate::object_store::KvStoreError),
696    #[error("Invalid `key` value used: {0}.")]
697    KeyValidationError(#[from] crate::object_store::KeyValidationError),
698    #[error("'{0}' is not a valid format for the config store. Supported format(s) are: 'json'.")]
699    InvalidFileFormat(String),
700    #[error("When using a top-level 'file' to load data, both 'file' and 'format' must be set.")]
701    OnlyOneFormatOrFileSet,
702    #[error(
703        "The file is of the wrong format. The file is expected to contain a single JSON Object."
704    )]
705    FileWrongFormat,
706    #[error("Item value under key named '{key}' is of the wrong format. The value is expected to be a JSON String.")]
707    FileValueWrongFormat { key: String },
708    #[error("Item value under key named '{key}' is of the wrong format. 'data' and 'file' are mutually exclusive.")]
709    BothDataAndFilePresent { key: String },
710    #[error("Item value under key named '{key}' is of the wrong format. One of 'data' or 'file' must be present.")]
711    MissingDataOrFile { key: String },
712}
713
714/// Errors that may occur while validating secret store configurations.
715#[derive(Debug, thiserror::Error)]
716pub enum SecretStoreConfigError {
717    /// An I/O error that occured while reading the file.
718    #[error(transparent)]
719    IoError(std::io::Error),
720
721    #[error("'{0}' is not a valid format for the secret store. Supported format(s) are: 'json'.")]
722    InvalidFileFormat(String),
723    #[error("When using a top-level 'file' to load data, both 'file' and 'format' must be set.")]
724    OnlyOneFormatOrFileSet,
725    #[error(
726        "The file is of the wrong format. The file is expected to contain a single JSON object."
727    )]
728    FileWrongFormat,
729    #[error("The `file` and `data` keys for the object `{0}` are set. Only one can be used.")]
730    FileAndData(String),
731    #[error("The `file` or `data` key for the object `{0}` is not set. One must be used.")]
732    NoFileOrData(String),
733    #[error("The `data` value for the object `{0}` is not a string.")]
734    DataNotAString(String),
735    #[error("The `file` value for the object `{0}` is not a string.")]
736    FileNotAString(String),
737
738    #[error("The `key` key for an object is not set. It must be used.")]
739    NoKey,
740    #[error("The `key` value for an object is not a string.")]
741    KeyNotAString,
742
743    #[error("There is no array of objects for the given store.")]
744    NotAnArray,
745    #[error("There is an object in the given store that is not a table of keys.")]
746    NotATable,
747
748    #[error("Invalid secret store name: {0}")]
749    InvalidSecretStoreName(String),
750
751    #[error("Invalid secret name: {0}")]
752    InvalidSecretName(String),
753}
754
755/// Errors that may occur while validating shielding site configurations.
756#[derive(Debug, thiserror::Error)]
757pub enum ShieldingSiteConfigError {
758    #[error("Illegal TOML value for shielding site; must be either the string 'local' or a table containin an encrypted and unencrypted URL.")]
759    IllegalSiteValue,
760
761    #[error("Illegal TOML string for shielding site; must be 'local'")]
762    IllegalSiteString,
763
764    #[error("Illegal table for shielding site; must have exactly one key named 'encrypted', and one named 'unencrypted'")]
765    IllegalSiteDefinition,
766
767    #[error("Illegal URL ({url}): {error}")]
768    IllegalUrl { url: String, error: url::ParseError },
769}
770
771/// Errors related to the downstream request.
772#[derive(Debug, thiserror::Error)]
773pub enum DownstreamRequestError {
774    #[error("Request HOST header is missing or invalid")]
775    InvalidHost,
776
777    #[error("Request URL is invalid")]
778    InvalidUrl,
779}