aws_credential_types/provider/
error.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Credentials provider errors
7
8use std::error::Error;
9use std::fmt;
10use std::time::Duration;
11
12/// Details for [`CredentialsError::CredentialsNotLoaded`]
13#[derive(Debug)]
14pub struct CredentialsNotLoaded {
15    source: Option<Box<dyn Error + Send + Sync + 'static>>,
16}
17
18/// Details for [`CredentialsError::ProviderTimedOut`] or [`TokenError::ProviderTimedOut`]
19#[derive(Debug)]
20pub struct ProviderTimedOut {
21    timeout_duration: Duration,
22}
23
24impl ProviderTimedOut {
25    /// Returns the maximum allowed timeout duration that was exceeded
26    pub fn timeout_duration(&self) -> Duration {
27        self.timeout_duration
28    }
29}
30
31/// Details for [`CredentialsError::InvalidConfiguration`] or [`TokenError::InvalidConfiguration`]
32#[derive(Debug)]
33pub struct InvalidConfiguration {
34    source: Box<dyn Error + Send + Sync + 'static>,
35}
36
37/// Details for [`CredentialsError::ProviderError`] or [`TokenError::ProviderError`]
38#[derive(Debug)]
39pub struct ProviderError {
40    source: Box<dyn Error + Send + Sync + 'static>,
41}
42
43/// Details for [`CredentialsError::Unhandled`] or [`TokenError::Unhandled`]
44#[derive(Debug)]
45pub struct Unhandled {
46    source: Box<dyn Error + Send + Sync + 'static>,
47}
48
49/// Error returned when credentials failed to load.
50#[derive(Debug)]
51#[non_exhaustive]
52pub enum CredentialsError {
53    /// No credentials were available for this provider
54    CredentialsNotLoaded(CredentialsNotLoaded),
55
56    /// Loading credentials from this provider exceeded the maximum allowed duration
57    ProviderTimedOut(ProviderTimedOut),
58
59    /// The provider was given an invalid configuration
60    ///
61    /// For example:
62    /// - syntax error in ~/.aws/config
63    /// - assume role profile that forms an infinite loop
64    InvalidConfiguration(InvalidConfiguration),
65
66    /// The provider experienced an error during credential resolution
67    ///
68    /// This may include errors like a 503 from STS or a file system error when attempting to
69    /// read a configuration file.
70    ProviderError(ProviderError),
71
72    /// An unexpected error occurred during credential resolution
73    ///
74    /// If the error is something that can occur during expected usage of a provider, `ProviderError`
75    /// should be returned instead. Unhandled is reserved for exceptional cases, for example:
76    /// - Returned data not UTF-8
77    /// - A provider returns data that is missing required fields
78    Unhandled(Unhandled),
79}
80
81impl CredentialsError {
82    /// The credentials provider did not provide credentials
83    ///
84    /// This error indicates the credentials provider was not enable or no configuration was set.
85    /// This contrasts with [`invalid_configuration`](CredentialsError::InvalidConfiguration), indicating
86    /// that the provider was configured in some way, but certain settings were invalid.
87    pub fn not_loaded(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
88        CredentialsError::CredentialsNotLoaded(CredentialsNotLoaded {
89            source: Some(source.into()),
90        })
91    }
92
93    /// The credentials provider did not provide credentials
94    ///
95    /// This error indicates the credentials provider was not enable or no configuration was set.
96    /// This contrasts with [`invalid_configuration`](CredentialsError::InvalidConfiguration), indicating
97    /// that the provider was configured in some way, but certain settings were invalid.
98    pub fn not_loaded_no_source() -> Self {
99        CredentialsError::CredentialsNotLoaded(CredentialsNotLoaded { source: None })
100    }
101
102    /// An unexpected error occurred loading credentials from this provider
103    ///
104    /// Unhandled errors should not occur during normal operation and should be reserved for exceptional
105    /// cases, such as a JSON API returning an output that was not parseable as JSON.
106    pub fn unhandled(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
107        Self::Unhandled(Unhandled {
108            source: source.into(),
109        })
110    }
111
112    /// The credentials provider returned an error
113    ///
114    /// Provider errors may occur during normal use of a credentials provider, e.g. a 503 when
115    /// retrieving credentials from IMDS.
116    pub fn provider_error(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
117        Self::ProviderError(ProviderError {
118            source: source.into(),
119        })
120    }
121
122    /// The provided configuration for a provider was invalid
123    pub fn invalid_configuration(
124        source: impl Into<Box<dyn Error + Send + Sync + 'static>>,
125    ) -> Self {
126        Self::InvalidConfiguration(InvalidConfiguration {
127            source: source.into(),
128        })
129    }
130
131    /// The credentials provider did not provide credentials within an allotted duration
132    pub fn provider_timed_out(timeout_duration: Duration) -> Self {
133        Self::ProviderTimedOut(ProviderTimedOut { timeout_duration })
134    }
135}
136
137impl fmt::Display for CredentialsError {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        match self {
140            CredentialsError::CredentialsNotLoaded(_) => {
141                write!(f, "the credential provider was not enabled")
142            }
143            CredentialsError::ProviderTimedOut(details) => write!(
144                f,
145                "credentials provider timed out after {} seconds",
146                details.timeout_duration.as_secs()
147            ),
148            CredentialsError::InvalidConfiguration(_) => {
149                write!(f, "the credentials provider was not properly configured")
150            }
151            CredentialsError::ProviderError(_) => {
152                write!(f, "an error occurred while loading credentials")
153            }
154            CredentialsError::Unhandled(_) => {
155                write!(f, "unexpected credentials error")
156            }
157        }
158    }
159}
160
161impl Error for CredentialsError {
162    fn source(&self) -> Option<&(dyn Error + 'static)> {
163        match self {
164            CredentialsError::CredentialsNotLoaded(details) => {
165                details.source.as_ref().map(|s| s.as_ref() as _)
166            }
167            CredentialsError::ProviderTimedOut(_) => None,
168            CredentialsError::InvalidConfiguration(details) => Some(details.source.as_ref() as _),
169            CredentialsError::ProviderError(details) => Some(details.source.as_ref() as _),
170            CredentialsError::Unhandled(details) => Some(details.source.as_ref() as _),
171        }
172    }
173}
174
175/// Details for [`TokenError::TokenNotLoaded`]
176#[derive(Debug)]
177pub struct TokenNotLoaded {
178    source: Box<dyn Error + Send + Sync + 'static>,
179}
180
181/// Error returned when an access token provider fails to provide an access token.
182#[derive(Debug)]
183pub enum TokenError {
184    /// This provider couldn't provide a token.
185    TokenNotLoaded(TokenNotLoaded),
186
187    /// Loading a token from this provider exceeded the maximum allowed time.
188    ProviderTimedOut(ProviderTimedOut),
189
190    /// The provider was given invalid configuration.
191    ///
192    /// For example, a syntax error in `~/.aws/config`.
193    InvalidConfiguration(InvalidConfiguration),
194
195    /// The provider experienced an error during credential resolution.
196    ProviderError(ProviderError),
197
198    /// An unexpected error occurred during token resolution.
199    ///
200    /// If the error is something that can occur during expected usage of a provider, `ProviderError`
201    /// should be returned instead. Unhandled is reserved for exceptional cases, for example:
202    /// - Returned data not UTF-8
203    /// - A provider returns data that is missing required fields
204    Unhandled(Unhandled),
205}
206
207impl TokenError {
208    /// The access token provider couldn't provide a token.
209    ///
210    /// This error indicates the token provider was not enable or no configuration was set.
211    /// This contrasts with [`invalid_configuration`](TokenError::InvalidConfiguration), indicating
212    /// that the provider was configured in some way, but certain settings were invalid.
213    pub fn not_loaded(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
214        TokenError::TokenNotLoaded(TokenNotLoaded {
215            source: source.into(),
216        })
217    }
218
219    /// An unexpected error occurred loading an access token from this provider.
220    ///
221    /// Unhandled errors should not occur during normal operation and should be reserved for exceptional
222    /// cases, such as a JSON API returning an output that was not parseable as JSON.
223    pub fn unhandled(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
224        Self::Unhandled(Unhandled {
225            source: source.into(),
226        })
227    }
228
229    /// The access token provider returned an error.
230    pub fn provider_error(source: impl Into<Box<dyn Error + Send + Sync + 'static>>) -> Self {
231        Self::ProviderError(ProviderError {
232            source: source.into(),
233        })
234    }
235
236    /// The provided configuration for a provider was invalid.
237    pub fn invalid_configuration(
238        source: impl Into<Box<dyn Error + Send + Sync + 'static>>,
239    ) -> Self {
240        Self::InvalidConfiguration(InvalidConfiguration {
241            source: source.into(),
242        })
243    }
244
245    /// The access token provider did not provide a token within an allotted amount of time.
246    pub fn provider_timed_out(timeout_duration: Duration) -> Self {
247        Self::ProviderTimedOut(ProviderTimedOut { timeout_duration })
248    }
249}
250
251impl fmt::Display for TokenError {
252    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253        match self {
254            TokenError::TokenNotLoaded(_) => {
255                write!(f, "the access token provider was not enabled")
256            }
257            TokenError::ProviderTimedOut(details) => write!(
258                f,
259                "access token provider timed out after {} seconds",
260                details.timeout_duration.as_secs()
261            ),
262            TokenError::InvalidConfiguration(_) => {
263                write!(f, "the access token provider was not properly configured")
264            }
265            TokenError::ProviderError(_) => {
266                write!(f, "an error occurred while loading an access token")
267            }
268            TokenError::Unhandled(_) => {
269                write!(f, "unexpected access token providererror")
270            }
271        }
272    }
273}
274
275impl Error for TokenError {
276    fn source(&self) -> Option<&(dyn Error + 'static)> {
277        match self {
278            TokenError::TokenNotLoaded(details) => Some(details.source.as_ref() as _),
279            TokenError::ProviderTimedOut(_) => None,
280            TokenError::InvalidConfiguration(details) => Some(details.source.as_ref() as _),
281            TokenError::ProviderError(details) => Some(details.source.as_ref() as _),
282            TokenError::Unhandled(details) => Some(details.source.as_ref() as _),
283        }
284    }
285}