couchbase_core/queryx/
error.rs

1/*
2 *
3 *  * Copyright (c) 2025 Couchbase, Inc.
4 *  *
5 *  * Licensed under the Apache License, Version 2.0 (the "License");
6 *  * you may not use this file except in compliance with the License.
7 *  * You may obtain a copy of the License at
8 *  *
9 *  *    http://www.apache.org/licenses/LICENSE-2.0
10 *  *
11 *  * Unless required by applicable law or agreed to in writing, software
12 *  * distributed under the License is distributed on an "AS IS" BASIS,
13 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  * See the License for the specific language governing permissions and
15 *  * limitations under the License.
16 *
17 */
18
19use http::StatusCode;
20use serde_json::Value;
21use std::collections::HashMap;
22use std::error::Error as StdError;
23use std::fmt::{Display, Formatter};
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27#[derive(Debug, Clone, PartialEq)]
28pub struct Error {
29    inner: ErrorImpl,
30}
31
32impl Display for Error {
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        write!(f, "{}", self.inner.kind)
35    }
36}
37
38impl StdError for Error {}
39
40impl Error {
41    pub(crate) fn new_server_error(e: ServerError) -> Error {
42        Self {
43            inner: ErrorImpl {
44                kind: Box::new(ErrorKind::Server(e)),
45            },
46        }
47    }
48
49    pub(crate) fn new_resource_error(e: ResourceError) -> Error {
50        Self {
51            inner: ErrorImpl {
52                kind: Box::new(ErrorKind::Resource(e)),
53            },
54        }
55    }
56
57    pub(crate) fn new_message_error(
58        msg: impl Into<String>,
59        endpoint: impl Into<Option<String>>,
60        statement: impl Into<Option<String>>,
61        client_context_id: impl Into<Option<String>>,
62    ) -> Error {
63        Self {
64            inner: ErrorImpl {
65                kind: Box::new(ErrorKind::Message {
66                    msg: msg.into(),
67                    endpoint: endpoint.into(),
68                    statement: statement.into(),
69                    client_context_id: client_context_id.into(),
70                }),
71            },
72        }
73    }
74
75    pub(crate) fn new_encoding_error(msg: impl Into<String>) -> Error {
76        Self {
77            inner: ErrorImpl {
78                kind: Box::new(ErrorKind::Encoding { msg: msg.into() }),
79            },
80        }
81    }
82
83    pub(crate) fn new_invalid_argument_error(
84        msg: impl Into<String>,
85        arg: impl Into<Option<String>>,
86    ) -> Self {
87        Self {
88            inner: ErrorImpl {
89                kind: Box::new(ErrorKind::InvalidArgument {
90                    msg: msg.into(),
91                    arg: arg.into(),
92                }),
93            },
94        }
95    }
96
97    pub(crate) fn new_http_error(
98        endpoint: impl Into<String>,
99        statement: impl Into<Option<String>>,
100        client_context_id: impl Into<Option<String>>,
101    ) -> Self {
102        Self {
103            inner: ErrorImpl {
104                kind: Box::new(ErrorKind::Http {
105                    endpoint: endpoint.into(),
106                    statement: statement.into(),
107                    client_context_id: client_context_id.into(),
108                }),
109            },
110        }
111    }
112
113    pub fn kind(&self) -> &ErrorKind {
114        &self.inner.kind
115    }
116}
117
118#[derive(Debug, Clone)]
119struct ErrorImpl {
120    kind: Box<ErrorKind>,
121}
122
123impl PartialEq for ErrorImpl {
124    fn eq(&self, other: &Self) -> bool {
125        self.kind == other.kind
126    }
127}
128
129#[derive(Clone, Debug, PartialEq, Eq)]
130#[non_exhaustive]
131pub enum ErrorKind {
132    Server(ServerError),
133    #[non_exhaustive]
134    Http {
135        endpoint: String,
136        statement: Option<String>,
137        client_context_id: Option<String>,
138    },
139    Resource(ResourceError),
140    #[non_exhaustive]
141    Message {
142        msg: String,
143        endpoint: Option<String>,
144        statement: Option<String>,
145        client_context_id: Option<String>,
146    },
147    #[non_exhaustive]
148    InvalidArgument {
149        msg: String,
150        arg: Option<String>,
151    },
152    #[non_exhaustive]
153    Encoding {
154        msg: String,
155    },
156}
157
158impl Display for ErrorKind {
159    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
160        match self {
161            ErrorKind::Server(e) => write!(f, "{e}"),
162            ErrorKind::Resource(e) => write!(f, "{e}"),
163            ErrorKind::InvalidArgument { msg, arg } => {
164                let base_msg = format!("invalid argument: {msg}");
165                if let Some(arg) = arg {
166                    write!(f, "{base_msg}, arg: {arg}")
167                } else {
168                    write!(f, "{base_msg}")
169                }
170            }
171            ErrorKind::Encoding { msg } => write!(f, "encoding error: {msg}"),
172            ErrorKind::Http {
173                endpoint,
174                statement,
175                client_context_id,
176            } => {
177                write!(f, "http error: endpoint: {endpoint}")?;
178                if let Some(statement) = statement {
179                    write!(f, ", statement: {statement}")?;
180                }
181                if let Some(client_context_id) = client_context_id {
182                    write!(f, ", client context id: {client_context_id}")?;
183                }
184                Ok(())
185            }
186            ErrorKind::Message {
187                msg,
188                endpoint,
189                statement,
190                client_context_id,
191            } => {
192                write!(f, "{msg}")?;
193                if let Some(endpoint) = endpoint {
194                    write!(f, ", endpoint: {endpoint}")?;
195                }
196                if let Some(statement) = statement {
197                    write!(f, ", statement: {statement}")?;
198                }
199                if let Some(client_context_id) = client_context_id {
200                    write!(f, ", client context id: {client_context_id}")?;
201                }
202                Ok(())
203            }
204        }
205    }
206}
207
208#[derive(Clone, Debug, PartialEq, Eq)]
209pub struct ServerError {
210    kind: ServerErrorKind,
211
212    endpoint: String,
213    status_code: StatusCode,
214    code: u32,
215    msg: String,
216
217    statement: Option<String>,
218    client_context_id: Option<String>,
219
220    all_error_descs: Vec<ErrorDesc>,
221}
222
223impl ServerError {
224    pub(crate) fn new(
225        kind: ServerErrorKind,
226        endpoint: impl Into<String>,
227        status_code: StatusCode,
228        code: u32,
229        msg: impl Into<String>,
230    ) -> Self {
231        Self {
232            kind,
233            endpoint: endpoint.into(),
234            status_code,
235            code,
236            msg: msg.into(),
237            statement: None,
238            client_context_id: None,
239            all_error_descs: vec![],
240        }
241    }
242
243    pub fn kind(&self) -> &ServerErrorKind {
244        &self.kind
245    }
246
247    pub fn endpoint(&self) -> &str {
248        &self.endpoint
249    }
250
251    pub fn statement(&self) -> Option<&str> {
252        self.statement.as_deref()
253    }
254
255    pub fn status_code(&self) -> StatusCode {
256        self.status_code
257    }
258
259    pub fn client_context_id(&self) -> Option<&str> {
260        self.client_context_id.as_deref()
261    }
262
263    pub fn code(&self) -> u32 {
264        self.code
265    }
266
267    pub fn msg(&self) -> &str {
268        &self.msg
269    }
270
271    pub fn all_error_descs(&self) -> &[ErrorDesc] {
272        &self.all_error_descs
273    }
274
275    pub(crate) fn with_statement(mut self, statement: impl Into<String>) -> Self {
276        self.statement = Some(statement.into());
277        self
278    }
279
280    pub(crate) fn with_client_context_id(mut self, client_context_id: impl Into<String>) -> Self {
281        self.client_context_id = Some(client_context_id.into());
282        self
283    }
284
285    pub(crate) fn with_error_descs(mut self, error_descs: Vec<ErrorDesc>) -> Self {
286        self.all_error_descs = error_descs;
287        self
288    }
289}
290
291impl Display for ServerError {
292    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
293        write!(
294            f,
295            "server error of kind: {} code: {}, msg: {}",
296            self.kind, self.code, self.msg
297        )?;
298
299        if let Some(client_context_id) = &self.client_context_id {
300            write!(f, ", client context id: {client_context_id}")?;
301        }
302        if let Some(statement) = &self.statement {
303            write!(f, ", statement: {statement}")?;
304        }
305
306        write!(
307            f,
308            ", endpoint: {},  status code: {}",
309            self.endpoint, self.status_code
310        )?;
311
312        if !self.all_error_descs.is_empty() {
313            write!(f, ", all error descriptions: {:?}", self.all_error_descs)?;
314        }
315
316        Ok(())
317    }
318}
319
320#[derive(Clone, Debug, PartialEq, Eq)]
321#[non_exhaustive]
322pub struct ResourceError {
323    cause: ServerError,
324    bucket_name: Option<String>,
325    scope_name: Option<String>,
326    collection_name: Option<String>,
327    index_name: Option<String>,
328}
329
330impl ResourceError {
331    pub(crate) fn new(cause: ServerError) -> Self {
332        match cause.kind {
333            ServerErrorKind::CollectionNotFound => Self::parse_resource_not_found(cause),
334            ServerErrorKind::ScopeNotFound => Self::parse_resource_not_found(cause),
335            ServerErrorKind::AuthenticationFailure => Self::parse_auth_failure(cause),
336            ServerErrorKind::IndexNotFound => Self::parse_index_not_found_or_exists(cause),
337            ServerErrorKind::IndexExists => Self::parse_index_not_found_or_exists(cause),
338            _ => Self {
339                cause,
340                bucket_name: None,
341                scope_name: None,
342                collection_name: None,
343                index_name: None,
344            },
345        }
346    }
347
348    pub fn cause(&self) -> &ServerError {
349        &self.cause
350    }
351
352    pub fn bucket_name(&self) -> Option<&str> {
353        self.bucket_name.as_deref()
354    }
355
356    pub fn scope_name(&self) -> Option<&str> {
357        self.scope_name.as_deref()
358    }
359
360    pub fn collection_name(&self) -> Option<&str> {
361        self.collection_name.as_deref()
362    }
363
364    pub fn index_name(&self) -> Option<&str> {
365        self.index_name.as_deref()
366    }
367
368    fn parse_index_not_found_or_exists(cause: ServerError) -> ResourceError {
369        let msg = cause.msg.clone();
370        let mut fields = msg.split_whitespace();
371
372        // msg for not found is of the form - "Index Not Found - cause: GSI index testingIndex not found."
373        // msg for index exists is of the form - "The index NewIndex already exists."
374        while let Some(field) = fields.next() {
375            if field == "index" {
376                return ResourceError {
377                    cause,
378                    bucket_name: None,
379                    scope_name: None,
380                    collection_name: None,
381                    index_name: Some(fields.next().unwrap().to_string()),
382                };
383            }
384        }
385
386        ResourceError {
387            cause,
388            bucket_name: None,
389            scope_name: None,
390            collection_name: None,
391            index_name: None,
392        }
393    }
394
395    fn parse_resource_not_found(cause: ServerError) -> ResourceError {
396        let msg = cause.msg.clone();
397        let mut fields = msg.split_whitespace();
398        // Resource path is of the form bucket:bucket.scope.collection
399        let path = fields.find(|f| f.contains('.') && f.contains(':'));
400
401        if let Some(p) = path {
402            if let Some(trimmed_path) = p.split(':').nth(1) {
403                let fields: Vec<&str> = trimmed_path.split('.').collect();
404
405                if cause.kind == ServerErrorKind::ScopeNotFound {
406                    // Bucket names are the only one that can contain `.`, which is why we need to reconstruct the name if split
407                    let bucket_name = fields[0..fields.len() - 1].join(".");
408                    let scope_name = fields[fields.len() - 1];
409
410                    return ResourceError {
411                        cause,
412                        bucket_name: Some(bucket_name),
413                        scope_name: Some(scope_name.to_string()),
414                        collection_name: None,
415                        index_name: None,
416                    };
417                } else if cause.kind == ServerErrorKind::CollectionNotFound {
418                    // Bucket names are the only one that can contain `.`, which is why we need to reconstruct the name if split
419                    let bucket_name = fields[0..fields.len() - 2].join(".");
420                    let scope_name = fields[fields.len() - 2];
421                    let collection_name = fields[fields.len() - 1];
422
423                    return ResourceError {
424                        cause,
425                        bucket_name: Some(bucket_name),
426                        scope_name: Some(scope_name.to_string()),
427                        collection_name: Some(collection_name.to_string()),
428                        index_name: None,
429                    };
430                }
431            }
432        }
433
434        ResourceError {
435            cause,
436            bucket_name: None,
437            scope_name: None,
438            collection_name: None,
439            index_name: None,
440        }
441    }
442
443    fn parse_auth_failure(cause: ServerError) -> Self {
444        let msg = &cause.msg;
445        let mut fields = msg.split_whitespace();
446        let path = fields.find(|f| f.contains(':'));
447
448        if let Some(p) = path {
449            if let Some(trimmed_path) = p.split(':').nth(1) {
450                let (bucket_name, scope_name, collection_name) = if trimmed_path.contains('`') {
451                    // trimmedPath will have the form "`bucket.name`" or "`bucket.name`.scope.collection" so the first element of fields
452                    // will be the empty string
453                    let fields: Vec<&str> = trimmed_path.split('`').collect();
454
455                    let bucket_name = fields[1];
456
457                    let (scope_name, collection_name) = if fields[2].is_empty() {
458                        (None, None)
459                    } else {
460                        // scope_and_col is of the form ".scope.collection" meaning fields[1] is empty and the names are in fields[1] and
461                        // fields[2]
462                        let scope_and_col = fields[2];
463                        let fields: Vec<&str> = scope_and_col.split('.').collect();
464                        let (scope, collection) = if fields.len() >= 3 {
465                            (Some(fields[1].to_string()), Some(fields[2].to_string()))
466                        } else {
467                            (None, None)
468                        };
469
470                        (scope, collection)
471                    };
472
473                    (Some(bucket_name.to_string()), scope_name, collection_name)
474                } else {
475                    let fields: Vec<&str> = trimmed_path.split('.').collect();
476
477                    let bucket_name = fields[0];
478
479                    let (scope_name, collection_name) = if fields.len() >= 3 {
480                        (Some(fields[1].to_string()), Some(fields[2].to_string()))
481                    } else {
482                        (None, None)
483                    };
484
485                    (Some(bucket_name.to_string()), scope_name, collection_name)
486                };
487
488                return ResourceError {
489                    cause,
490                    bucket_name,
491                    scope_name,
492                    collection_name,
493                    index_name: None,
494                };
495            }
496        }
497
498        ResourceError {
499            cause,
500            bucket_name: None,
501            scope_name: None,
502            collection_name: None,
503            index_name: None,
504        }
505    }
506}
507
508impl Display for ResourceError {
509    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
510        write!(f, "resource error caused by: {}", self.cause)?;
511
512        if let Some(bucket_name) = &self.bucket_name {
513            write!(f, ", bucket: {bucket_name}")?;
514        }
515        if let Some(scope_name) = &self.scope_name {
516            write!(f, ", scope: {scope_name}")?;
517        }
518        if let Some(collection_name) = &self.collection_name {
519            write!(f, ", collection: {collection_name}")?;
520        }
521        if let Some(index_name) = &self.index_name {
522            write!(f, ", index: {index_name}")?;
523        }
524
525        Ok(())
526    }
527}
528
529impl StdError for ResourceError {}
530
531#[derive(Clone, Debug, PartialEq, Eq)]
532#[non_exhaustive]
533pub struct ErrorDesc {
534    kind: ServerErrorKind,
535
536    code: u32,
537    message: String,
538    retry: bool,
539    reason: HashMap<String, Value>,
540}
541
542impl ErrorDesc {
543    pub fn new(
544        kind: ServerErrorKind,
545        code: u32,
546        message: String,
547        retry: bool,
548        reason: HashMap<String, Value>,
549    ) -> Self {
550        Self {
551            kind,
552            code,
553            message,
554            retry,
555            reason,
556        }
557    }
558
559    pub fn kind(&self) -> &ServerErrorKind {
560        &self.kind
561    }
562
563    pub fn code(&self) -> u32 {
564        self.code
565    }
566
567    pub fn message(&self) -> &str {
568        &self.message
569    }
570
571    pub fn retry(&self) -> bool {
572        self.retry
573    }
574
575    pub fn reason(&self) -> &HashMap<String, Value> {
576        &self.reason
577    }
578}
579
580impl Display for ErrorDesc {
581    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
582        write!(
583            f,
584            "error description of kind: {}, code: {}, message: {}, retry: {}, reason: {:?}",
585            self.kind, self.code, self.message, self.retry, self.reason
586        )
587    }
588}
589
590#[derive(Clone, Debug, PartialEq, Eq)]
591#[non_exhaustive]
592pub enum ServerErrorKind {
593    ParsingFailure,
594    Internal,
595    AuthenticationFailure,
596    CasMismatch,
597    DocNotFound,
598    DocExists,
599    PlanningFailure,
600    IndexFailure,
601    PreparedStatementFailure,
602    DMLFailure,
603    Timeout,
604    IndexExists,
605    IndexNotFound,
606    WriteInReadOnlyMode,
607    ScopeNotFound,
608    CollectionNotFound,
609    InvalidArgument { argument: String, reason: String },
610    BuildAlreadyInProgress,
611    Unknown,
612}
613
614impl Display for ServerErrorKind {
615    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
616        match self {
617            ServerErrorKind::ParsingFailure => write!(f, "parsing failure"),
618            ServerErrorKind::Internal => write!(f, "internal server error"),
619            ServerErrorKind::AuthenticationFailure => write!(f, "authentication failure"),
620            ServerErrorKind::CasMismatch => write!(f, "cas mismatch"),
621            ServerErrorKind::DocNotFound => write!(f, "doc not found"),
622            ServerErrorKind::DocExists => write!(f, "doc exists"),
623            ServerErrorKind::PlanningFailure => write!(f, "planning failure"),
624            ServerErrorKind::IndexFailure => write!(f, "index failure"),
625            ServerErrorKind::PreparedStatementFailure => write!(f, "prepared statement failure"),
626            ServerErrorKind::DMLFailure => write!(
627                f,
628                "data service returned an error during execution of DML statement"
629            ),
630            ServerErrorKind::Timeout => write!(f, "server timeout"),
631            ServerErrorKind::IndexExists => write!(f, "index exists"),
632            ServerErrorKind::IndexNotFound => write!(f, "index not found"),
633            ServerErrorKind::WriteInReadOnlyMode => {
634                write!(f, "write statement used in a read-only query")
635            }
636            ServerErrorKind::ScopeNotFound => write!(f, "scope not found"),
637            ServerErrorKind::CollectionNotFound => write!(f, "collection not found"),
638            ServerErrorKind::InvalidArgument { argument, reason } => write!(
639                f,
640                "server invalid argument: (argument: {argument}, reason: {reason})"
641            ),
642            ServerErrorKind::BuildAlreadyInProgress => write!(f, "build already in progress"),
643            ServerErrorKind::Unknown => write!(f, "unknown query error"),
644        }
645    }
646}
647
648impl Error {
649    pub fn is_parsing_failure(&self) -> bool {
650        matches!(
651            self.kind(),
652            ErrorKind::Server(ServerError {
653                kind: ServerErrorKind::ParsingFailure,
654                ..
655            })
656        )
657    }
658
659    pub fn is_internal(&self) -> bool {
660        matches!(
661            self.kind(),
662            ErrorKind::Server(ServerError {
663                kind: ServerErrorKind::Internal,
664                ..
665            })
666        )
667    }
668
669    pub fn is_authentication_failure(&self) -> bool {
670        matches!(
671            self.kind(),
672            ErrorKind::Server(ServerError {
673                kind: ServerErrorKind::AuthenticationFailure,
674                ..
675            })
676        )
677    }
678
679    pub fn is_cas_mismatch(&self) -> bool {
680        matches!(
681            self.kind(),
682            ErrorKind::Server(ServerError {
683                kind: ServerErrorKind::CasMismatch,
684                ..
685            })
686        )
687    }
688
689    pub fn is_doc_not_found(&self) -> bool {
690        matches!(
691            self.kind(),
692            ErrorKind::Server(ServerError {
693                kind: ServerErrorKind::DocNotFound,
694                ..
695            })
696        )
697    }
698
699    pub fn is_doc_exists(&self) -> bool {
700        matches!(
701            self.kind(),
702            ErrorKind::Server(ServerError {
703                kind: ServerErrorKind::DocExists,
704                ..
705            })
706        )
707    }
708
709    pub fn is_planning_failure(&self) -> bool {
710        matches!(
711            self.kind(),
712            ErrorKind::Server(ServerError {
713                kind: ServerErrorKind::PlanningFailure,
714                ..
715            })
716        )
717    }
718
719    pub fn is_index_failure(&self) -> bool {
720        matches!(
721            self.kind(),
722            ErrorKind::Server(ServerError {
723                kind: ServerErrorKind::IndexFailure,
724                ..
725            })
726        )
727    }
728
729    pub fn is_prepared_statement_failure(&self) -> bool {
730        matches!(
731            self.kind(),
732            ErrorKind::Server(ServerError {
733                kind: ServerErrorKind::PreparedStatementFailure,
734                ..
735            })
736        )
737    }
738
739    pub fn is_dml_failure(&self) -> bool {
740        matches!(
741            self.kind(),
742            ErrorKind::Server(ServerError {
743                kind: ServerErrorKind::DMLFailure,
744                ..
745            })
746        )
747    }
748
749    pub fn is_server_timeout(&self) -> bool {
750        matches!(
751            self.kind(),
752            ErrorKind::Server(ServerError {
753                kind: ServerErrorKind::Timeout,
754                ..
755            })
756        )
757    }
758
759    pub fn is_write_in_read_only_mode(&self) -> bool {
760        matches!(
761            self.kind(),
762            ErrorKind::Server(ServerError {
763                kind: ServerErrorKind::WriteInReadOnlyMode,
764                ..
765            })
766        )
767    }
768
769    pub fn is_invalid_argument(&self) -> bool {
770        matches!(
771            self.kind(),
772            ErrorKind::Server(ServerError {
773                kind: ServerErrorKind::InvalidArgument { .. },
774                ..
775            })
776        )
777    }
778
779    pub fn is_build_already_in_progress(&self) -> bool {
780        matches!(
781            self.kind(),
782            ErrorKind::Server(ServerError {
783                kind: ServerErrorKind::BuildAlreadyInProgress,
784                ..
785            })
786        )
787    }
788
789    pub fn is_scope_not_found(&self) -> bool {
790        matches!(
791            self.kind(),
792            ErrorKind::Resource(ResourceError {
793                cause: ServerError {
794                    kind: ServerErrorKind::ScopeNotFound,
795                    ..
796                },
797                ..
798            })
799        ) || matches!(
800            self.kind(),
801            ErrorKind::Server(ServerError {
802                kind: ServerErrorKind::ScopeNotFound,
803                ..
804            })
805        )
806    }
807
808    pub fn is_collection_not_found(&self) -> bool {
809        matches!(
810            self.kind(),
811            ErrorKind::Resource(ResourceError {
812                cause: ServerError {
813                    kind: ServerErrorKind::CollectionNotFound,
814                    ..
815                },
816                ..
817            })
818        ) || matches!(
819            self.kind(),
820            ErrorKind::Server(ServerError {
821                kind: ServerErrorKind::CollectionNotFound,
822                ..
823            })
824        )
825    }
826
827    pub fn is_index_not_found(&self) -> bool {
828        matches!(
829            self.kind(),
830            ErrorKind::Resource(ResourceError {
831                cause: ServerError {
832                    kind: ServerErrorKind::IndexNotFound,
833                    ..
834                },
835                ..
836            })
837        ) || matches!(
838            self.kind(),
839            ErrorKind::Server(ServerError {
840                kind: ServerErrorKind::IndexNotFound,
841                ..
842            })
843        )
844    }
845
846    pub fn is_index_exists(&self) -> bool {
847        matches!(
848            self.kind(),
849            ErrorKind::Resource(ResourceError {
850                cause: ServerError {
851                    kind: ServerErrorKind::IndexExists,
852                    ..
853                },
854                ..
855            })
856        ) || matches!(
857            self.kind(),
858            ErrorKind::Server(ServerError {
859                kind: ServerErrorKind::IndexExists,
860                ..
861            })
862        )
863    }
864}