1pub(crate) mod bulk_write;
4
5use std::{
6 any::Any,
7 collections::{HashMap, HashSet},
8 fmt::{self, Debug},
9 sync::Arc,
10};
11
12use serde::{Deserialize, Serialize};
13use thiserror::Error;
14
15use crate::{
16 bson::{doc, rawdoc, Bson, Document, RawDocumentBuf},
17 cmap::RawCommandResponse,
18 options::ServerAddress,
19 sdam::{ServerType, TopologyVersion},
20};
21
22pub use bulk_write::{BulkWriteError, PartialBulkWriteResult};
23
24pub(crate) const RECOVERING_CODES: [i32; 5] = [11600, 11602, 13436, 189, 91];
27pub(crate) const NOTWRITABLEPRIMARY_CODES: [i32; 3] = [10107, 13435, 10058];
29pub(crate) const SHUTTING_DOWN_CODES: [i32; 2] = [11600, 91];
32pub(crate) const RETRYABLE_READ_CODES: [i32; 13] = [
35 11600, 11602, 10107, 13435, 13436, 189, 91, 7, 6, 89, 9001, 134, 262,
36];
37pub(crate) const RETRYABLE_WRITE_CODES: [i32; 12] = [
40 11600, 11602, 10107, 13435, 13436, 189, 91, 7, 6, 89, 9001, 262,
41];
42const UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL_CODES: [i32; 3] = [50, 64, 91];
43const REAUTHENTICATION_REQUIRED_CODE: i32 = 391;
44const CURSOR_NOT_FOUND_CODE: i32 = 43;
46const RESUMABLE_CHANGE_STREAM_CODES: [i32; 17] = [
50 6, 7, 89, 91, 189, 262, 9001, 10107, 11600, 11602, 13435, 13436, 63, 150, 13388, 234, 133,
51];
52
53pub const RETRYABLE_WRITE_ERROR: &str = "RetryableWriteError";
56pub const TRANSIENT_TRANSACTION_ERROR: &str = "TransientTransactionError";
59pub const UNKNOWN_TRANSACTION_COMMIT_RESULT: &str = "UnknownTransactionCommitResult";
63pub const SYSTEM_OVERLOADED_ERROR: &str = "SystemOverloadedError";
66pub const RETRYABLE_ERROR: &str = "RetryableError";
68pub const NO_WRITES_PERFORMED: &str = "NoWritesPerformed";
70
71pub type Result<T> = std::result::Result<T, Error>;
73
74#[derive(Clone, Debug, Error)]
78#[cfg_attr(
79 feature = "error-backtrace",
80 error(
81 "Kind: {kind}, labels: {labels:?}, source: {source:?}, server response: \
82 {server_response:?}, backtrace: {backtrace}"
83 )
84)]
85#[cfg_attr(
86 not(feature = "error-backtrace"),
87 error(
88 "Kind: {kind}, labels: {labels:?}, source: {source:?}, server response: \
89 {server_response:?}"
90 )
91)]
92#[non_exhaustive]
93pub struct Error {
94 pub kind: Box<ErrorKind>,
96
97 labels: HashSet<String>,
98
99 pub(crate) wire_version: Option<i32>,
100
101 #[source]
102 pub(crate) source: Option<Box<Error>>,
103
104 pub(crate) server_response: Option<Box<RawDocumentBuf>>,
105
106 #[cfg(feature = "error-backtrace")]
107 pub(crate) backtrace: Arc<std::backtrace::Backtrace>,
108}
109
110impl Error {
111 pub fn custom(e: impl Any + Send + Sync) -> Self {
114 Self::new(ErrorKind::Custom(Arc::new(e)), None::<Option<String>>)
115 }
116
117 pub fn get_custom<E: Any>(&self) -> Option<&E> {
120 if let ErrorKind::Custom(c) = &*self.kind {
121 c.downcast_ref()
122 } else {
123 None
124 }
125 }
126
127 pub(crate) fn new(kind: ErrorKind, labels: Option<impl IntoIterator<Item = String>>) -> Self {
128 let mut labels: HashSet<String> = labels
129 .map(|labels| labels.into_iter().collect())
130 .unwrap_or_default();
131 if let Some(wc) = kind.get_write_concern_error() {
132 labels.extend(wc.labels.clone());
133 }
134 Self {
135 kind: Box::new(kind),
136 labels,
137 wire_version: None,
138 source: None,
139 server_response: None,
140 #[cfg(feature = "error-backtrace")]
141 backtrace: Arc::new(std::backtrace::Backtrace::capture()),
142 }
143 }
144
145 pub(crate) fn pool_cleared_error(address: &ServerAddress, cause: &Error) -> Self {
146 ErrorKind::ConnectionPoolCleared {
147 message: format!(
148 "Connection pool for {} cleared because another operation failed with: {cause}",
149 Redact(address)
150 ),
151 }
152 .into()
153 }
154
155 pub(crate) fn authentication_error(mechanism_name: &str, reason: &str) -> Self {
157 ErrorKind::Authentication {
158 message: format!("{mechanism_name} failure: {reason}"),
159 }
160 .into()
161 }
162
163 pub(crate) fn unknown_authentication_error(mechanism_name: &str) -> Error {
165 Error::authentication_error(mechanism_name, "internal error")
166 }
167
168 pub(crate) fn invalid_authentication_response(mechanism_name: &str) -> Error {
171 Error::authentication_error(mechanism_name, "invalid server response")
172 }
173
174 pub(crate) fn internal(message: impl Into<String>) -> Error {
175 ErrorKind::Internal {
176 message: message.into(),
177 }
178 .into()
179 }
180
181 pub(crate) fn invalid_response(message: impl Into<String>) -> Error {
182 ErrorKind::InvalidResponse {
183 message: message.into(),
184 }
185 .into()
186 }
187
188 pub(crate) fn network_timeout() -> Error {
190 ErrorKind::Io(Arc::new(std::io::ErrorKind::TimedOut.into())).into()
191 }
192
193 pub(crate) fn invalid_argument(message: impl Into<String>) -> Error {
194 ErrorKind::InvalidArgument {
195 message: message.into(),
196 }
197 .into()
198 }
199
200 pub(crate) fn is_state_change_error(&self) -> bool {
201 self.is_recovering() || self.is_notwritableprimary()
202 }
203
204 pub(crate) fn is_auth_error(&self) -> bool {
205 matches!(self.kind.as_ref(), ErrorKind::Authentication { .. })
206 }
207
208 #[cfg(all(feature = "in-use-encryption", test))]
209 pub(crate) fn is_command_error(&self) -> bool {
210 matches!(self.kind.as_ref(), ErrorKind::Command(_))
211 }
212
213 pub(crate) fn is_network_timeout(&self) -> bool {
214 matches!(self.kind.as_ref(), ErrorKind::Io(ref io_err) if io_err.kind() == std::io::ErrorKind::TimedOut)
215 }
216
217 pub(crate) fn is_ns_not_found(&self) -> bool {
219 matches!(self.kind.as_ref(), ErrorKind::Command(ref err) if err.code == 26)
220 }
221
222 pub(crate) fn is_server_selection_error(&self) -> bool {
223 matches!(self.kind.as_ref(), ErrorKind::ServerSelection { .. })
224 }
225
226 pub(crate) fn is_max_time_ms_expired_error(&self) -> bool {
227 self.sdam_code() == Some(50)
228 }
229
230 pub(crate) fn is_read_retryable(&self) -> bool {
232 if self.is_network_error() {
233 return true;
234 }
235 match self.sdam_code() {
236 Some(code) => RETRYABLE_READ_CODES.contains(&code),
237 None => false,
238 }
239 }
240
241 pub(crate) fn is_write_retryable(&self) -> bool {
242 self.contains_label(RETRYABLE_WRITE_ERROR)
243 }
244
245 fn is_write_concern_error(&self) -> bool {
246 match *self.kind {
247 ErrorKind::Write(WriteFailure::WriteConcernError(_)) => true,
248 ErrorKind::InsertMany(ref insert_many_error)
249 if insert_many_error.write_concern_error.is_some() =>
250 {
251 true
252 }
253 _ => false,
254 }
255 }
256
257 pub(crate) fn should_add_retryable_write_label(
262 &self,
263 max_wire_version: Option<i32>,
264 server_type: Option<ServerType>,
265 ) -> bool {
266 const SERVER_4_2_0_WIRE_VERSION: i32 = 8;
267
268 if max_wire_version
269 .map(|mwv| mwv > SERVER_4_2_0_WIRE_VERSION)
270 .unwrap_or(true)
271 {
272 return self.is_network_error();
273 }
274 if self.is_network_error() {
275 return true;
276 }
277
278 if server_type == Some(ServerType::Mongos) && self.is_write_concern_error() {
279 return false;
280 }
281
282 match &self.sdam_code() {
283 Some(code) => RETRYABLE_WRITE_CODES.contains(code),
284 None => false,
285 }
286 }
287
288 pub(crate) fn should_add_unknown_transaction_commit_result_label(&self) -> bool {
289 if self.contains_label(TRANSIENT_TRANSACTION_ERROR) {
290 return false;
291 }
292 if self.is_network_error() || self.is_server_selection_error() || self.is_write_retryable()
293 {
294 return true;
295 }
296 match self.sdam_code() {
297 Some(code) => UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL_CODES.contains(&code),
298 None => false,
299 }
300 }
301
302 pub(crate) fn is_server_error(&self) -> bool {
304 matches!(
305 self.kind.as_ref(),
306 ErrorKind::Authentication { .. }
307 | ErrorKind::InsertMany(_)
308 | ErrorKind::Command(_)
309 | ErrorKind::Write(_)
310 )
311 }
312
313 pub fn labels(&self) -> &HashSet<String> {
315 &self.labels
316 }
317
318 pub fn contains_label<T: AsRef<str>>(&self, label: T) -> bool {
320 let label = label.as_ref();
321 self.labels().contains(label)
322 || self
323 .source
324 .as_ref()
325 .map(|source| source.contains_label(label))
326 .unwrap_or(false)
327 }
328
329 pub(crate) fn add_label<T: AsRef<str>>(&mut self, label: T) {
331 let label = label.as_ref().to_string();
332 self.labels.insert(label);
333 }
334
335 pub(crate) fn with_backpressure_labels(mut self) -> Self {
336 if self.is_network_error() {
337 self.add_label(SYSTEM_OVERLOADED_ERROR);
338 self.add_label(RETRYABLE_ERROR);
339 }
340 self
341 }
342
343 pub fn server_response(&self) -> Option<&RawDocumentBuf> {
346 self.server_response.as_deref()
347 }
348
349 pub(crate) fn with_server_response(mut self, response: &RawCommandResponse) -> Self {
351 if self.server_response.is_none() {
352 self.server_response = Some(Box::new(response.raw_body().to_owned()));
353 }
354 self
355 }
356
357 #[cfg(feature = "dns-resolver")]
358 pub(crate) fn from_resolve_error(error: hickory_net::NetError) -> Self {
359 ErrorKind::DnsResolve {
360 message: error.to_string(),
361 }
362 .into()
363 }
364
365 #[cfg(feature = "dns-resolver")]
366 pub(crate) fn from_resolve_proto_error(error: hickory_proto::ProtoError) -> Self {
367 ErrorKind::DnsResolve {
368 message: error.to_string(),
369 }
370 .into()
371 }
372
373 pub(crate) fn is_non_timeout_network_error(&self) -> bool {
374 matches!(self.kind.as_ref(), ErrorKind::Io(ref io_err) if io_err.kind() != std::io::ErrorKind::TimedOut)
375 }
376
377 pub(crate) fn is_network_error(&self) -> bool {
378 #[cfg(feature = "socks5-proxy")]
379 if matches!(self.kind.as_ref(), ErrorKind::ProxyConnect { .. }) {
380 return true;
381 }
382 matches!(
383 self.kind.as_ref(),
384 ErrorKind::Io(..) | ErrorKind::ConnectionPoolCleared { .. }
385 )
386 }
387
388 #[cfg(all(test, feature = "in-use-encryption"))]
389 pub(crate) fn is_csfle_error(&self) -> bool {
390 matches!(self.kind.as_ref(), ErrorKind::Encryption(..))
391 }
392
393 pub(crate) fn sdam_code(&self) -> Option<i32> {
396 match self.kind.as_ref() {
397 ErrorKind::Command(command_error) => Some(command_error.code),
398 ErrorKind::InsertMany(InsertManyError {
401 write_concern_error: Some(wc_error),
402 ..
403 }) => Some(wc_error.code),
404 ErrorKind::Write(WriteFailure::WriteConcernError(wc_error)) => Some(wc_error.code),
405 _ => None,
406 }
407 .or_else(|| self.source.as_ref().and_then(|s| s.sdam_code()))
408 }
409
410 #[cfg(test)]
412 pub(crate) fn code(&self) -> Option<i32> {
413 match self.kind.as_ref() {
414 ErrorKind::Command(command_error) => Some(command_error.code),
415 ErrorKind::InsertMany(InsertManyError {
416 write_concern_error: Some(wc_error),
417 ..
418 }) => Some(wc_error.code),
419 ErrorKind::Write(e) => Some(e.code()),
420 _ => None,
421 }
422 .or_else(|| self.source.as_ref().and_then(|s| s.sdam_code()))
423 }
424
425 #[cfg(test)]
428 pub(crate) fn message(&self) -> Option<String> {
429 match self.kind.as_ref() {
430 ErrorKind::Command(command_error) => Some(command_error.message.clone()),
431 ErrorKind::InsertMany(InsertManyError {
435 write_concern_error,
436 write_errors,
437 inserted_ids: _,
438 }) => {
439 let mut msg = "".to_string();
440 if let Some(wc_error) = write_concern_error {
441 msg.push_str(wc_error.message.as_str());
442 }
443 if let Some(write_errors) = write_errors {
444 for we in write_errors {
445 msg.push_str(we.message.as_str());
446 }
447 }
448 Some(msg)
449 }
450 ErrorKind::Write(WriteFailure::WriteConcernError(wc_error)) => {
451 Some(wc_error.message.clone())
452 }
453 ErrorKind::Write(WriteFailure::WriteError(write_error)) => {
454 Some(write_error.message.clone())
455 }
456 ErrorKind::Transaction { message } => Some(message.clone()),
457 ErrorKind::IncompatibleServer { message } => Some(message.clone()),
458 ErrorKind::InvalidArgument { message } => Some(message.clone()),
459 #[cfg(feature = "in-use-encryption")]
460 ErrorKind::Encryption(err) => err.message.clone(),
461 _ => None,
462 }
463 }
464
465 #[cfg(test)]
467 pub(crate) fn code_name(&self) -> Option<&str> {
468 match self.kind.as_ref() {
469 ErrorKind::Command(ref cmd_err) => Some(cmd_err.code_name.as_str()),
470 ErrorKind::Write(ref failure) => match failure {
471 WriteFailure::WriteConcernError(ref wce) => Some(wce.code_name.as_str()),
472 WriteFailure::WriteError(ref we) => we.code_name.as_deref(),
473 },
474 ErrorKind::InsertMany(ref bwe) => bwe
475 .write_concern_error
476 .as_ref()
477 .map(|wce| wce.code_name.as_str()),
478 _ => None,
479 }
480 }
481
482 pub(crate) fn is_notwritableprimary(&self) -> bool {
484 self.sdam_code()
485 .map(|code| NOTWRITABLEPRIMARY_CODES.contains(&code))
486 .unwrap_or(false)
487 }
488
489 pub(crate) fn is_reauthentication_required(&self) -> bool {
491 self.sdam_code() == Some(REAUTHENTICATION_REQUIRED_CODE)
492 }
493
494 pub(crate) fn is_recovering(&self) -> bool {
496 self.sdam_code()
497 .map(|code| RECOVERING_CODES.contains(&code))
498 .unwrap_or(false)
499 }
500
501 pub(crate) fn is_shutting_down(&self) -> bool {
503 self.sdam_code()
504 .map(|code| SHUTTING_DOWN_CODES.contains(&code))
505 .unwrap_or(false)
506 }
507
508 pub(crate) fn is_pool_cleared(&self) -> bool {
509 matches!(self.kind.as_ref(), ErrorKind::ConnectionPoolCleared { .. })
510 }
511
512 pub(crate) fn is_resumable(&self) -> bool {
514 if !self.is_server_error() {
515 return true;
516 }
517 let code = self.sdam_code();
518 if code == Some(CURSOR_NOT_FOUND_CODE) {
519 return true;
520 }
521 if matches!(self.wire_version, Some(v) if v >= 9)
522 && self.contains_label("ResumableChangeStreamError")
523 {
524 return true;
525 }
526 if let (Some(code), true) = (code, matches!(self.wire_version, Some(v) if v < 9)) {
527 if RESUMABLE_CHANGE_STREAM_CODES.contains(&code) {
528 return true;
529 }
530 }
531 false
532 }
533
534 pub(crate) fn is_incompatible_server(&self) -> bool {
535 matches!(self.kind.as_ref(), ErrorKind::IncompatibleServer { .. })
536 }
537
538 #[allow(unused)]
539 pub(crate) fn is_invalid_argument(&self) -> bool {
540 matches!(self.kind.as_ref(), ErrorKind::InvalidArgument { .. })
541 }
542
543 pub(crate) fn with_source<E: Into<Option<Error>>>(mut self, source: E) -> Self {
544 self.source = source.into().map(Box::new);
545 self
546 }
547
548 pub(crate) fn topology_version(&self) -> Option<TopologyVersion> {
549 match self.kind.as_ref() {
550 ErrorKind::Command(c) => c.topology_version,
551 _ => None,
552 }
553 }
554
555 pub(crate) fn redact(&mut self) {
560 if let Some(source) = self.source.as_deref_mut() {
561 source.redact();
562 }
563
564 if self.server_response.is_some() {
565 self.server_response = Some(Box::new(rawdoc! { "redacted": true }));
566 }
567
568 match *self.kind {
571 ErrorKind::InsertMany(ref mut insert_many_error) => {
572 if let Some(ref mut wes) = insert_many_error.write_errors {
573 for we in wes {
574 we.redact();
575 }
576 }
577 if let Some(ref mut wce) = insert_many_error.write_concern_error {
578 wce.redact();
579 }
580 }
581 ErrorKind::BulkWrite(ref mut bulk_write_error) => {
582 for write_concern_error in bulk_write_error.write_concern_errors.iter_mut() {
583 write_concern_error.redact();
584 }
585 for (_, write_error) in bulk_write_error.write_errors.iter_mut() {
586 write_error.redact();
587 }
588 }
589 ErrorKind::Command(ref mut command_error) => {
590 command_error.redact();
591 }
592 ErrorKind::Write(ref mut write_error) => match write_error {
593 WriteFailure::WriteConcernError(wce) => {
594 wce.redact();
595 }
596 WriteFailure::WriteError(we) => {
597 we.redact();
598 }
599 },
600 ErrorKind::InvalidArgument { .. }
601 | ErrorKind::BsonDeserialization(_)
602 | ErrorKind::BsonSerialization(_)
603 | ErrorKind::DnsResolve { .. }
604 | ErrorKind::Io(_)
605 | ErrorKind::Internal { .. }
606 | ErrorKind::ConnectionPoolCleared { .. }
607 | ErrorKind::InvalidResponse { .. }
608 | ErrorKind::ServerSelection { .. }
609 | ErrorKind::SessionsNotSupported
610 | ErrorKind::InvalidTlsConfig { .. }
611 | ErrorKind::Transaction { .. }
612 | ErrorKind::IncompatibleServer { .. }
613 | ErrorKind::MissingResumeToken
614 | ErrorKind::Authentication { .. }
615 | ErrorKind::Custom(_)
616 | ErrorKind::Shutdown
617 | ErrorKind::GridFs(_) => {}
618 #[cfg(feature = "socks5-proxy")]
619 ErrorKind::ProxyConnect { .. } => {}
620 #[cfg(feature = "in-use-encryption")]
621 ErrorKind::Encryption(_) => {}
622 #[cfg(feature = "bson-3")]
623 ErrorKind::Bson(_) => {}
624 }
625 }
626}
627
628impl<E> From<E> for Error
629where
630 ErrorKind: From<E>,
631{
632 fn from(err: E) -> Self {
633 Error::new(err.into(), None::<Option<String>>)
634 }
635}
636
637#[cfg(not(feature = "bson-3"))]
638impl From<crate::bson::de::Error> for ErrorKind {
639 fn from(err: crate::bson::de::Error) -> Self {
640 Self::BsonDeserialization(err)
641 }
642}
643
644#[cfg(not(feature = "bson-3"))]
645impl From<crate::bson::ser::Error> for ErrorKind {
646 fn from(err: crate::bson::ser::Error) -> Self {
647 Self::BsonSerialization(err)
648 }
649}
650
651#[cfg(not(feature = "bson-3"))]
652impl From<crate::bson_compat::RawError> for ErrorKind {
653 fn from(err: crate::bson_compat::RawError) -> Self {
654 Self::InvalidResponse {
655 message: err.to_string(),
656 }
657 }
658}
659
660#[cfg(not(feature = "bson-3"))]
661impl From<crate::bson::raw::ValueAccessError> for ErrorKind {
662 fn from(err: crate::bson::raw::ValueAccessError) -> Self {
663 Self::InvalidResponse {
664 message: err.to_string(),
665 }
666 }
667}
668
669#[cfg(feature = "bson-3")]
670impl From<crate::bson::error::Error> for ErrorKind {
671 fn from(err: crate::bson::error::Error) -> Self {
672 Self::Bson(err)
673 }
674}
675
676impl From<std::io::Error> for ErrorKind {
677 fn from(err: std::io::Error) -> Self {
678 Self::Io(Arc::new(err))
679 }
680}
681
682impl From<std::io::ErrorKind> for ErrorKind {
683 fn from(err: std::io::ErrorKind) -> Self {
684 Self::Io(Arc::new(err.into()))
685 }
686}
687
688#[cfg(feature = "in-use-encryption")]
689impl From<mongocrypt::error::Error> for ErrorKind {
690 fn from(err: mongocrypt::error::Error) -> Self {
691 Self::Encryption(err)
692 }
693}
694
695impl From<std::convert::Infallible> for ErrorKind {
696 fn from(_err: std::convert::Infallible) -> Self {
697 unreachable!()
698 }
699}
700
701#[allow(missing_docs)]
703#[derive(Clone, Debug, Error)]
704#[non_exhaustive]
705pub enum ErrorKind {
706 #[error("An invalid argument was provided: {message}")]
708 #[non_exhaustive]
709 InvalidArgument { message: String },
710
711 #[error("{message}")]
714 #[non_exhaustive]
715 Authentication { message: String },
716
717 #[error("{0}")]
719 BsonDeserialization(crate::bson_compat::DeError),
720
721 #[error("{0}")]
723 BsonSerialization(crate::bson_compat::SerError),
724
725 #[cfg(feature = "bson-3")]
727 #[error("{0}")]
728 Bson(crate::bson::error::Error),
729
730 #[error("An error occurred when trying to execute an insert_many operation: {0:?}")]
733 InsertMany(InsertManyError),
734
735 #[error("An error occurred when executing Client::bulk_write: {0:?}")]
736 BulkWrite(BulkWriteError),
737
738 #[error("Command failed: {0}")]
740 Command(CommandError),
743
744 #[error("An error occurred during DNS resolution: {message}")]
746 #[non_exhaustive]
747 DnsResolve { message: String },
748
749 #[error("{0:?}")]
751 GridFs(GridFsErrorKind),
752
753 #[error("Internal error: {message}")]
754 #[non_exhaustive]
755 Internal { message: String },
756
757 #[error("I/O error: {0}")]
759 Io(Arc<std::io::Error>),
762
763 #[error("{message}")]
766 #[non_exhaustive]
767 ConnectionPoolCleared { message: String },
768
769 #[error("The server returned an invalid reply to a database operation: {message}")]
771 #[non_exhaustive]
772 InvalidResponse { message: String },
773
774 #[error("{message}")]
776 #[non_exhaustive]
777 ServerSelection { message: String },
778
779 #[error("Attempted to start a session on a deployment that does not support sessions")]
781 SessionsNotSupported,
782
783 #[error("{message}")]
784 #[non_exhaustive]
785 InvalidTlsConfig { message: String },
786
787 #[error("An error occurred when trying to execute a write operation: {0:?}")]
789 Write(WriteFailure),
790
791 #[error("{message}")]
793 #[non_exhaustive]
794 Transaction { message: String },
795
796 #[error("The server does not support a database operation: {message}")]
798 #[non_exhaustive]
799 IncompatibleServer { message: String },
800
801 #[error("Cannot provide resume functionality when the resume token is missing")]
803 MissingResumeToken,
804
805 #[cfg(feature = "in-use-encryption")]
807 #[error("An error occurred during client-side encryption: {0}")]
808 Encryption(mongocrypt::error::Error),
809
810 #[error("Custom user error{string}", string = display_custom(.0))]
812 Custom(Arc<dyn Any + Send + Sync>),
813
814 #[error("Client has been shut down")]
816 Shutdown,
817
818 #[error("An error occurred when connecting to a proxy host: {message}")]
820 #[non_exhaustive]
821 #[cfg(feature = "socks5-proxy")]
822 ProxyConnect { message: String },
823}
824
825fn display_custom(custom: &Arc<dyn Any + Send + Sync>) -> String {
826 if let Some(string) = custom.downcast_ref::<String>() {
827 format!(": {string}")
828 } else {
829 String::new()
830 }
831}
832
833impl ErrorKind {
834 fn get_write_concern_error(&self) -> Option<&WriteConcernError> {
838 match self {
839 ErrorKind::InsertMany(InsertManyError {
840 write_concern_error,
841 ..
842 }) => write_concern_error.as_ref(),
843 ErrorKind::Write(WriteFailure::WriteConcernError(err)) => Some(err),
844 _ => None,
845 }
846 }
847
848 #[cfg(feature = "opentelemetry")]
849 pub(crate) fn name(&self) -> &'static str {
850 match self {
851 ErrorKind::InvalidArgument { .. } => "InvalidArgument",
852 ErrorKind::Authentication { .. } => "Authentication",
853 ErrorKind::BsonDeserialization(..) => "BsonDeserialization",
854 ErrorKind::BsonSerialization(..) => "BsonSerialization",
855 #[cfg(feature = "bson-3")]
856 ErrorKind::Bson(..) => "Bson",
857 ErrorKind::InsertMany(..) => "InsertMany",
858 ErrorKind::BulkWrite(..) => "BulkWrite",
859 ErrorKind::Command(..) => "Command",
860 ErrorKind::DnsResolve { .. } => "DnsResolve",
861 ErrorKind::GridFs(..) => "GridFs",
862 ErrorKind::Internal { .. } => "Internal",
863 ErrorKind::Io(..) => "Io",
864 ErrorKind::ConnectionPoolCleared { .. } => "ConnectionPoolCleared",
865 ErrorKind::InvalidResponse { .. } => "InvalidResponse",
866 ErrorKind::ServerSelection { .. } => "ServerSelection",
867 ErrorKind::SessionsNotSupported => "SessionsNotSupported",
868 ErrorKind::InvalidTlsConfig { .. } => "InvalidTlsConfig",
869 ErrorKind::Write(..) => "Write",
870 ErrorKind::Transaction { .. } => "Transaction",
871 ErrorKind::IncompatibleServer { .. } => "IncompatibleServer",
872 ErrorKind::MissingResumeToken => "MissingResumeToken",
873 #[cfg(feature = "in-use-encryption")]
874 ErrorKind::Encryption(..) => "Encryption",
875 ErrorKind::Custom(..) => "Custom",
876 ErrorKind::Shutdown => "Shutdown",
877 #[cfg(feature = "socks5-proxy")]
878 ErrorKind::ProxyConnect { .. } => "ProxyConnect",
879 }
880 }
881}
882
883#[derive(Clone, Debug, Serialize, Deserialize)]
885#[non_exhaustive]
886pub struct CommandError {
887 pub code: i32,
889
890 #[serde(rename = "codeName", default)]
892 pub code_name: String,
893
894 #[serde(rename = "errmsg", default = "String::new")]
896 pub message: String,
897
898 #[serde(rename = "topologyVersion")]
900 pub(crate) topology_version: Option<TopologyVersion>,
901}
902
903impl CommandError {
904 fn redact(&mut self) {
907 self.message = "REDACTED".to_string();
908 }
909}
910
911impl fmt::Display for CommandError {
912 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
915 write!(
916 fmt,
917 "Error code {} ({}): {}",
918 self.code, self.code_name, self.message
919 )
920 }
921}
922
923#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
925#[non_exhaustive]
926pub struct WriteConcernError {
927 pub code: i32,
929
930 #[serde(rename = "codeName", default)]
932 pub code_name: String,
933
934 #[serde(alias = "errmsg", default = "String::new")]
936 pub message: String,
937
938 #[serde(rename = "errInfo")]
940 pub details: Option<Document>,
941
942 #[serde(rename = "errorLabels", default)]
946 pub(crate) labels: Vec<String>,
947}
948
949impl WriteConcernError {
950 fn redact(&mut self) {
953 self.message = "REDACTED".to_string();
954 self.details = None;
955 }
956}
957
958#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
961#[non_exhaustive]
962pub struct WriteError {
963 pub code: i32,
965
966 #[serde(rename = "codeName", default)]
971 pub code_name: Option<String>,
972
973 #[serde(rename = "errmsg", default = "String::new")]
975 pub message: String,
976
977 #[serde(rename = "errInfo")]
980 pub details: Option<Document>,
981}
982
983impl WriteError {
984 fn redact(&mut self) {
987 self.message = "REDACTED".to_string();
988 self.details = None;
989 }
990}
991
992#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
995#[non_exhaustive]
996pub struct IndexedWriteError {
997 #[serde(default)]
999 pub index: usize,
1000
1001 pub code: i32,
1003
1004 #[serde(rename = "codeName", default)]
1009 pub code_name: Option<String>,
1010
1011 #[serde(rename = "errmsg", default = "String::new")]
1013 pub message: String,
1014
1015 #[serde(rename = "errInfo")]
1018 pub details: Option<Document>,
1019}
1020
1021impl IndexedWriteError {
1022 fn redact(&mut self) {
1025 self.message = "REDACTED".to_string();
1026 self.details = None;
1027 }
1028}
1029
1030#[derive(Clone, Debug, Serialize, Deserialize)]
1033#[serde(rename_all = "camelCase")]
1034#[non_exhaustive]
1035pub struct InsertManyError {
1036 pub write_errors: Option<Vec<IndexedWriteError>>,
1038
1039 pub write_concern_error: Option<WriteConcernError>,
1041
1042 #[serde(skip)]
1043 pub(crate) inserted_ids: HashMap<usize, Bson>,
1044}
1045
1046impl InsertManyError {
1047 pub(crate) fn new() -> Self {
1048 InsertManyError {
1049 write_errors: None,
1050 write_concern_error: None,
1051 inserted_ids: Default::default(),
1052 }
1053 }
1054}
1055
1056#[derive(Clone, Debug, Serialize, Deserialize)]
1058#[non_exhaustive]
1059pub enum WriteFailure {
1060 WriteConcernError(WriteConcernError),
1062
1063 WriteError(WriteError),
1066}
1067
1068impl WriteFailure {
1069 fn from_insert_many_error(bulk: InsertManyError) -> Result<Self> {
1070 if let Some(insert_error) = bulk.write_errors.and_then(|es| es.into_iter().next()) {
1071 let write_error = WriteError {
1072 code: insert_error.code,
1073 code_name: insert_error.code_name,
1074 message: insert_error.message,
1075 details: insert_error.details,
1076 };
1077 Ok(WriteFailure::WriteError(write_error))
1078 } else if let Some(wc_error) = bulk.write_concern_error {
1079 Ok(WriteFailure::WriteConcernError(wc_error))
1080 } else {
1081 Err(ErrorKind::InvalidResponse {
1082 message: "error missing write errors and write concern errors".to_string(),
1083 }
1084 .into())
1085 }
1086 }
1087
1088 #[cfg(test)]
1089 pub(crate) fn code(&self) -> i32 {
1090 match self {
1091 Self::WriteConcernError(e) => e.code,
1092 Self::WriteError(e) => e.code,
1093 }
1094 }
1095}
1096
1097#[derive(Clone, Debug)]
1099#[allow(missing_docs)]
1100#[non_exhaustive]
1101pub enum GridFsErrorKind {
1102 #[non_exhaustive]
1104 FileNotFound { identifier: GridFsFileIdentifier },
1105
1106 #[non_exhaustive]
1108 RevisionNotFound { revision: i32 },
1109
1110 #[non_exhaustive]
1112 MissingChunk { n: u32 },
1113
1114 UploadStreamClosed,
1117
1118 #[non_exhaustive]
1120 WrongSizeChunk {
1121 actual_size: usize,
1122 expected_size: u32,
1123 n: u32,
1124 },
1125
1126 #[non_exhaustive]
1128 WrongNumberOfChunks {
1129 actual_number: u32,
1130 expected_number: u32,
1131 },
1132
1133 #[non_exhaustive]
1135 AbortError {
1136 original_error: Option<Error>,
1139
1140 delete_error: Error,
1142 },
1143
1144 WriteInProgress,
1148}
1149
1150#[derive(Clone, Debug)]
1152#[non_exhaustive]
1153pub enum GridFsFileIdentifier {
1154 Filename(String),
1156
1157 Id(Bson),
1159}
1160
1161pub(crate) fn convert_insert_many_error(error: Error) -> Error {
1163 match *error.kind {
1164 ErrorKind::InsertMany(insert_many_error) => {
1165 match WriteFailure::from_insert_many_error(insert_many_error) {
1166 Ok(failure) => Error::new(ErrorKind::Write(failure), Some(error.labels)),
1167 Err(e) => e,
1168 }
1169 }
1170 _ => error,
1171 }
1172}
1173
1174macro_rules! load_balanced_mode_mismatch {
1178 ($e:expr) => {{
1179 if cfg!(debug_assertions) {
1180 panic!("load-balanced mode mismatch")
1181 }
1182 return $e;
1183 }};
1184 () => {
1185 load_balanced_mode_mismatch!(())
1186 };
1187}
1188
1189pub(crate) use load_balanced_mode_mismatch;
1190
1191pub(crate) struct Redact<T>(pub T);
1192
1193impl<T: std::fmt::Display> std::fmt::Display for Redact<T> {
1194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1195 if cfg!(feature = "redact-errors") {
1196 write!(f, "<redacted>")
1197 } else {
1198 write!(f, "{}", self.0)
1199 }
1200 }
1201}
1202
1203impl<T: std::fmt::Debug> std::fmt::Debug for Redact<T> {
1204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205 if cfg!(feature = "redact-errors") {
1206 write!(f, "<redacted>")
1207 } else {
1208 write!(f, "{:?}", self.0)
1209 }
1210 }
1211}