1use crate::client::connection::ConnectionMetadata;
9use aws_smithy_types::error::metadata::{ProvideErrorMetadata, EMPTY_ERROR_METADATA};
10use aws_smithy_types::error::operation::BuildError;
11use aws_smithy_types::error::ErrorMetadata;
12use aws_smithy_types::retry::ErrorKind;
13use std::error::Error;
14use std::fmt;
15use std::fmt::{Debug, Display, Formatter};
16
17type BoxError = Box<dyn Error + Send + Sync>;
18
19pub mod builders {
21 use super::*;
22
23 macro_rules! source_only_error_builder {
24 ($errorName:ident, $builderName:ident, $sourceType:ident) => {
25 #[doc = concat!("Builder for [`", stringify!($errorName), "`](super::", stringify!($errorName), ").")]
26 #[derive(Debug, Default)]
27 pub struct $builderName {
28 source: Option<$sourceType>,
29 }
30
31 impl $builderName {
32 #[doc = "Creates a new builder."]
33 pub fn new() -> Self { Default::default() }
34
35 #[doc = "Sets the error source."]
36 pub fn source(mut self, source: impl Into<$sourceType>) -> Self {
37 self.source = Some(source.into());
38 self
39 }
40
41 #[doc = "Sets the error source."]
42 pub fn set_source(&mut self, source: Option<$sourceType>) -> &mut Self {
43 self.source = source;
44 self
45 }
46
47 #[doc = "Builds the error context."]
48 pub fn build(self) -> $errorName {
49 $errorName { source: self.source.expect("source is required") }
50 }
51 }
52 };
53 }
54
55 source_only_error_builder!(ConstructionFailure, ConstructionFailureBuilder, BoxError);
56 source_only_error_builder!(TimeoutError, TimeoutErrorBuilder, BoxError);
57 source_only_error_builder!(DispatchFailure, DispatchFailureBuilder, ConnectorError);
58
59 #[derive(Debug)]
61 pub struct ResponseErrorBuilder<R> {
62 source: Option<BoxError>,
63 raw: Option<R>,
64 }
65
66 impl<R> Default for ResponseErrorBuilder<R> {
67 fn default() -> Self {
68 Self {
69 source: None,
70 raw: None,
71 }
72 }
73 }
74
75 impl<R> ResponseErrorBuilder<R> {
76 pub fn new() -> Self {
78 Default::default()
79 }
80
81 pub fn source(mut self, source: impl Into<BoxError>) -> Self {
83 self.source = Some(source.into());
84 self
85 }
86
87 pub fn set_source(&mut self, source: Option<BoxError>) -> &mut Self {
89 self.source = source;
90 self
91 }
92
93 pub fn raw(mut self, raw: R) -> Self {
95 self.raw = Some(raw);
96 self
97 }
98
99 pub fn set_raw(&mut self, raw: Option<R>) -> &mut Self {
101 self.raw = raw;
102 self
103 }
104
105 pub fn build(self) -> ResponseError<R> {
107 ResponseError {
108 source: self.source.expect("source is required"),
109 raw: self.raw.expect("a raw response is required"),
110 }
111 }
112 }
113
114 #[derive(Debug)]
116 pub struct ServiceErrorBuilder<E, R> {
117 source: Option<E>,
118 raw: Option<R>,
119 }
120
121 impl<E, R> Default for ServiceErrorBuilder<E, R> {
122 fn default() -> Self {
123 Self {
124 source: None,
125 raw: None,
126 }
127 }
128 }
129
130 impl<E, R> ServiceErrorBuilder<E, R> {
131 pub fn new() -> Self {
133 Default::default()
134 }
135
136 pub fn source(mut self, source: impl Into<E>) -> Self {
138 self.source = Some(source.into());
139 self
140 }
141
142 pub fn set_source(&mut self, source: Option<E>) -> &mut Self {
144 self.source = source;
145 self
146 }
147
148 pub fn raw(mut self, raw: R) -> Self {
150 self.raw = Some(raw);
151 self
152 }
153
154 pub fn set_raw(&mut self, raw: Option<R>) -> &mut Self {
156 self.raw = raw;
157 self
158 }
159
160 pub fn build(self) -> ServiceError<E, R> {
162 ServiceError {
163 source: self.source.expect("source is required"),
164 raw: self.raw.expect("a raw response is required"),
165 }
166 }
167 }
168}
169
170#[derive(Debug)]
172pub struct ConstructionFailure {
173 pub(crate) source: BoxError,
174}
175
176impl ConstructionFailure {
177 pub fn builder() -> builders::ConstructionFailureBuilder {
179 builders::ConstructionFailureBuilder::new()
180 }
181}
182
183#[derive(Debug)]
185pub struct TimeoutError {
186 source: BoxError,
187}
188
189impl TimeoutError {
190 pub fn builder() -> builders::TimeoutErrorBuilder {
192 builders::TimeoutErrorBuilder::new()
193 }
194}
195
196#[derive(Debug)]
198pub struct DispatchFailure {
199 source: ConnectorError,
200}
201
202impl DispatchFailure {
203 pub fn builder() -> builders::DispatchFailureBuilder {
205 builders::DispatchFailureBuilder::new()
206 }
207
208 pub fn is_io(&self) -> bool {
210 self.source.is_io()
211 }
212
213 pub fn is_timeout(&self) -> bool {
215 self.source.is_timeout()
216 }
217
218 pub fn is_user(&self) -> bool {
220 self.source.is_user()
221 }
222
223 pub fn is_other(&self) -> bool {
225 self.source.is_other()
226 }
227
228 pub fn as_other(&self) -> Option<ErrorKind> {
230 self.source.as_other()
231 }
232
233 pub fn as_connector_error(&self) -> Option<&ConnectorError> {
235 Some(&self.source)
236 }
237}
238
239#[derive(Debug)]
241pub struct ResponseError<R> {
242 source: BoxError,
244 raw: R,
246}
247
248impl<R> ResponseError<R> {
249 pub fn builder() -> builders::ResponseErrorBuilder<R> {
251 builders::ResponseErrorBuilder::new()
252 }
253
254 pub fn raw(&self) -> &R {
256 &self.raw
257 }
258
259 pub fn into_raw(self) -> R {
261 self.raw
262 }
263}
264
265#[derive(Debug)]
267pub struct ServiceError<E, R> {
268 source: E,
270 raw: R,
272}
273
274impl<E, R> ServiceError<E, R> {
275 pub fn builder() -> builders::ServiceErrorBuilder<E, R> {
277 builders::ServiceErrorBuilder::new()
278 }
279
280 pub fn err(&self) -> &E {
282 &self.source
283 }
284
285 pub fn into_err(self) -> E {
287 self.source
288 }
289
290 pub fn raw(&self) -> &R {
292 &self.raw
293 }
294
295 pub fn into_raw(self) -> R {
297 self.raw
298 }
299}
300
301pub trait CreateUnhandledError {
305 fn create_unhandled_error(
307 source: Box<dyn Error + Send + Sync + 'static>,
308 meta: Option<ErrorMetadata>,
309 ) -> Self;
310}
311
312#[non_exhaustive]
319#[derive(Debug)]
320pub enum SdkError<E, R> {
321 ConstructionFailure(ConstructionFailure),
323
324 TimeoutError(TimeoutError),
326
327 DispatchFailure(DispatchFailure),
330
331 ResponseError(ResponseError<R>),
334
335 ServiceError(ServiceError<E, R>),
337}
338
339impl<E, R> SdkError<E, R> {
340 pub fn construction_failure(source: impl Into<BoxError>) -> Self {
342 Self::ConstructionFailure(ConstructionFailure {
343 source: source.into(),
344 })
345 }
346
347 pub fn timeout_error(source: impl Into<BoxError>) -> Self {
349 Self::TimeoutError(TimeoutError {
350 source: source.into(),
351 })
352 }
353
354 pub fn dispatch_failure(source: ConnectorError) -> Self {
356 Self::DispatchFailure(DispatchFailure { source })
357 }
358
359 pub fn response_error(source: impl Into<BoxError>, raw: R) -> Self {
361 Self::ResponseError(ResponseError {
362 source: source.into(),
363 raw,
364 })
365 }
366
367 pub fn service_error(source: E, raw: R) -> Self {
369 Self::ServiceError(ServiceError { source, raw })
370 }
371
372 pub fn into_service_error(self) -> E
405 where
406 E: std::error::Error + Send + Sync + CreateUnhandledError + 'static,
407 R: Debug + Send + Sync + 'static,
408 {
409 match self {
410 Self::ServiceError(context) => context.source,
411 _ => E::create_unhandled_error(self.into(), None),
412 }
413 }
414
415 pub fn as_service_error(&self) -> Option<&E> {
439 match self {
440 Self::ServiceError(err) => Some(&err.source),
441 _ => None,
442 }
443 }
444
445 pub fn into_source(self) -> Result<Box<dyn Error + Send + Sync + 'static>, Self>
449 where
450 E: std::error::Error + Send + Sync + 'static,
451 {
452 match self {
453 SdkError::ConstructionFailure(context) => Ok(context.source),
454 SdkError::TimeoutError(context) => Ok(context.source),
455 SdkError::ResponseError(context) => Ok(context.source),
456 SdkError::DispatchFailure(context) => Ok(context.source.into()),
457 SdkError::ServiceError(context) => Ok(context.source.into()),
458 }
459 }
460
461 pub fn raw_response(&self) -> Option<&R> {
463 match self {
464 SdkError::ServiceError(inner) => Some(inner.raw()),
465 SdkError::ResponseError(inner) => Some(inner.raw()),
466 _ => None,
467 }
468 }
469
470 pub fn map_service_error<E2>(self, map: impl FnOnce(E) -> E2) -> SdkError<E2, R> {
472 match self {
473 SdkError::ServiceError(context) => SdkError::<E2, R>::ServiceError(ServiceError {
474 source: map(context.source),
475 raw: context.raw,
476 }),
477 SdkError::ConstructionFailure(context) => {
478 SdkError::<E2, R>::ConstructionFailure(context)
479 }
480 SdkError::DispatchFailure(context) => SdkError::<E2, R>::DispatchFailure(context),
481 SdkError::ResponseError(context) => SdkError::<E2, R>::ResponseError(context),
482 SdkError::TimeoutError(context) => SdkError::<E2, R>::TimeoutError(context),
483 }
484 }
485}
486
487impl<E, R> Display for SdkError<E, R> {
488 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
489 match self {
490 SdkError::ConstructionFailure(_) => write!(f, "failed to construct request"),
491 SdkError::TimeoutError(_) => write!(f, "request has timed out"),
492 SdkError::DispatchFailure(_) => write!(f, "dispatch failure"),
493 SdkError::ResponseError(_) => write!(f, "response error"),
494 SdkError::ServiceError(_) => write!(f, "service error"),
495 }
496 }
497}
498
499impl<E, R> Error for SdkError<E, R>
500where
501 E: Error + 'static,
502 R: Debug,
503{
504 fn source(&self) -> Option<&(dyn Error + 'static)> {
505 match self {
506 SdkError::ConstructionFailure(context) => Some(context.source.as_ref()),
507 SdkError::TimeoutError(context) => Some(context.source.as_ref()),
508 SdkError::ResponseError(context) => Some(context.source.as_ref()),
509 SdkError::DispatchFailure(context) => Some(&context.source),
510 SdkError::ServiceError(context) => Some(&context.source),
511 }
512 }
513}
514
515impl<E, R> From<BuildError> for SdkError<E, R> {
516 fn from(value: BuildError) -> Self {
517 SdkError::ConstructionFailure(ConstructionFailure::builder().source(value).build())
518 }
519}
520
521impl<E, R> ProvideErrorMetadata for SdkError<E, R>
522where
523 E: ProvideErrorMetadata,
524{
525 fn meta(&self) -> &aws_smithy_types::error::ErrorMetadata {
526 match self {
527 SdkError::ConstructionFailure(_) => &EMPTY_ERROR_METADATA,
528 SdkError::TimeoutError(_) => &EMPTY_ERROR_METADATA,
529 SdkError::DispatchFailure(_) => &EMPTY_ERROR_METADATA,
530 SdkError::ResponseError(_) => &EMPTY_ERROR_METADATA,
531 SdkError::ServiceError(err) => err.source.meta(),
532 }
533 }
534}
535
536#[derive(Debug)]
537enum ConnectorErrorKind {
538 Timeout,
540
541 User,
543
544 Io,
546
547 Other(Option<ErrorKind>),
549}
550
551#[derive(Debug)]
558pub struct ConnectorError {
559 kind: ConnectorErrorKind,
560 source: BoxError,
561 connection: ConnectionStatus,
562}
563
564#[non_exhaustive]
565#[derive(Debug)]
566pub(crate) enum ConnectionStatus {
567 NeverConnected,
571
572 Unknown,
574
575 Connected(ConnectionMetadata),
577}
578
579impl Display for ConnectorError {
580 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
581 match self.kind {
582 ConnectorErrorKind::Timeout => write!(f, "timeout"),
583 ConnectorErrorKind::User => write!(f, "user error"),
584 ConnectorErrorKind::Io => write!(f, "io error"),
585 ConnectorErrorKind::Other(_) => write!(f, "other"),
586 }
587 }
588}
589
590impl Error for ConnectorError {
591 fn source(&self) -> Option<&(dyn Error + 'static)> {
592 Some(self.source.as_ref())
593 }
594}
595
596impl ConnectorError {
597 pub fn timeout(source: BoxError) -> Self {
601 Self {
602 kind: ConnectorErrorKind::Timeout,
603 source,
604 connection: ConnectionStatus::Unknown,
605 }
606 }
607
608 pub fn with_connection(mut self, info: ConnectionMetadata) -> Self {
610 self.connection = ConnectionStatus::Connected(info);
611 self
612 }
613
614 pub fn never_connected(mut self) -> Self {
616 self.connection = ConnectionStatus::NeverConnected;
617 self
618 }
619
620 pub fn user(source: BoxError) -> Self {
622 Self {
623 kind: ConnectorErrorKind::User,
624 source,
625 connection: ConnectionStatus::Unknown,
626 }
627 }
628
629 pub fn io(source: BoxError) -> Self {
631 Self {
632 kind: ConnectorErrorKind::Io,
633 source,
634 connection: ConnectionStatus::Unknown,
635 }
636 }
637
638 pub fn other(source: BoxError, kind: Option<ErrorKind>) -> Self {
642 Self {
643 source,
644 kind: ConnectorErrorKind::Other(kind),
645 connection: ConnectionStatus::Unknown,
646 }
647 }
648
649 pub fn is_io(&self) -> bool {
651 matches!(self.kind, ConnectorErrorKind::Io)
652 }
653
654 pub fn is_timeout(&self) -> bool {
656 matches!(self.kind, ConnectorErrorKind::Timeout)
657 }
658
659 pub fn is_user(&self) -> bool {
661 matches!(self.kind, ConnectorErrorKind::User)
662 }
663
664 pub fn is_other(&self) -> bool {
666 matches!(self.kind, ConnectorErrorKind::Other(..))
667 }
668
669 pub fn as_other(&self) -> Option<ErrorKind> {
671 match &self.kind {
672 ConnectorErrorKind::Other(ek) => *ek,
673 _ => None,
674 }
675 }
676
677 pub fn into_source(self) -> BoxError {
679 self.source
680 }
681
682 pub fn connection_metadata(&self) -> Option<&ConnectionMetadata> {
687 match &self.connection {
688 ConnectionStatus::NeverConnected => None,
689 ConnectionStatus::Unknown => None,
690 ConnectionStatus::Connected(conn) => Some(conn),
691 }
692 }
693}