chroma_error/
lib.rs

1// Defines 17 standard error codes based on the error codes defined in the
2// gRPC spec. https://grpc.github.io/grpc/core/md_doc_statuscodes.html
3// Custom errors can use these codes in order to allow for generic handling
4use std::error::Error;
5
6#[cfg(feature = "tonic")]
7mod tonic;
8#[cfg(feature = "tonic")]
9pub use tonic::*;
10
11#[cfg(feature = "sqlx")]
12mod sqlx;
13#[cfg(feature = "sqlx")]
14pub use sqlx::*;
15
16#[cfg(feature = "validator")]
17mod validator;
18#[cfg(feature = "validator")]
19pub use validator::*;
20
21#[derive(PartialEq, Debug, Clone, Copy)]
22pub enum ErrorCodes {
23    // OK is returned on success, we use "Success" since Ok is a keyword in Rust.
24    Success = 0,
25    // CANCELLED indicates the operation was cancelled (typically by the caller).
26    Cancelled = 1,
27    // UNKNOWN indicates an unknown error.
28    Unknown = 2,
29    // INVALID_ARGUMENT indicates client specified an invalid argument.
30    InvalidArgument = 3,
31    // DEADLINE_EXCEEDED means operation expired before completion.
32    DeadlineExceeded = 4,
33    // NOT_FOUND means some requested entity (e.g., file or directory) was not found.
34    NotFound = 5,
35    // ALREADY_EXISTS means an entity that we attempted to create (e.g., file or directory) already exists.
36    AlreadyExists = 6,
37    // PERMISSION_DENIED indicates the caller does not have permission to execute the specified operation.
38    PermissionDenied = 7,
39    // RESOURCE_EXHAUSTED indicates some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.
40    ResourceExhausted = 8,
41    // FAILED_PRECONDITION indicates operation was rejected because the system is not in a state required for the operation's execution.
42    FailedPrecondition = 9,
43    // ABORTED indicates the operation was aborted.
44    Aborted = 10,
45    // OUT_OF_RANGE means operation was attempted past the valid range.
46    OutOfRange = 11,
47    // UNIMPLEMENTED indicates operation is not implemented or not supported/enabled.
48    Unimplemented = 12,
49    // INTERNAL errors are internal errors.
50    Internal = 13,
51    // UNAVAILABLE indicates service is currently unavailable.
52    Unavailable = 14,
53    // DATA_LOSS indicates unrecoverable data loss or corruption.
54    DataLoss = 15,
55    // UNAUTHENTICATED indicates the request does not have valid authentication credentials for the operation.
56    Unauthenticated = 16,
57    // VERSION_MISMATCH indicates a version mismatch. This is not from the gRPC spec and is specific to Chroma.
58    VersionMismatch = 17,
59    // UNPROCESSABLE_ENTITY indicates the request is valid but cannot be processed.
60    UnprocessableEntity = 18,
61}
62
63impl ErrorCodes {
64    pub fn name(&self) -> &'static str {
65        match self {
66            ErrorCodes::InvalidArgument => "InvalidArgumentError",
67            ErrorCodes::NotFound => "NotFoundError",
68            ErrorCodes::Internal => "InternalError",
69            ErrorCodes::VersionMismatch => "VersionMismatchError",
70            _ => "ChromaError",
71        }
72    }
73}
74
75#[cfg(feature = "http")]
76impl From<ErrorCodes> for http::StatusCode {
77    fn from(error_code: ErrorCodes) -> Self {
78        match error_code {
79            ErrorCodes::Success => http::StatusCode::OK,
80            ErrorCodes::Cancelled => http::StatusCode::BAD_REQUEST,
81            ErrorCodes::Unknown => http::StatusCode::INTERNAL_SERVER_ERROR,
82            ErrorCodes::InvalidArgument => http::StatusCode::BAD_REQUEST,
83            ErrorCodes::DeadlineExceeded => http::StatusCode::GATEWAY_TIMEOUT,
84            ErrorCodes::NotFound => http::StatusCode::NOT_FOUND,
85            ErrorCodes::AlreadyExists => http::StatusCode::CONFLICT,
86            ErrorCodes::PermissionDenied => http::StatusCode::FORBIDDEN,
87            ErrorCodes::ResourceExhausted => http::StatusCode::TOO_MANY_REQUESTS,
88            ErrorCodes::FailedPrecondition => http::StatusCode::PRECONDITION_FAILED,
89            ErrorCodes::Aborted => http::StatusCode::BAD_REQUEST,
90            ErrorCodes::OutOfRange => http::StatusCode::BAD_REQUEST,
91            ErrorCodes::Unimplemented => http::StatusCode::NOT_IMPLEMENTED,
92            ErrorCodes::Internal => http::StatusCode::INTERNAL_SERVER_ERROR,
93            ErrorCodes::Unavailable => http::StatusCode::SERVICE_UNAVAILABLE,
94            ErrorCodes::DataLoss => http::StatusCode::INTERNAL_SERVER_ERROR,
95            ErrorCodes::Unauthenticated => http::StatusCode::UNAUTHORIZED,
96            ErrorCodes::VersionMismatch => http::StatusCode::INTERNAL_SERVER_ERROR,
97            ErrorCodes::UnprocessableEntity => http::StatusCode::UNPROCESSABLE_ENTITY,
98        }
99    }
100}
101
102#[cfg(feature = "http")]
103impl From<http::StatusCode> for ErrorCodes {
104    fn from(value: http::StatusCode) -> Self {
105        match value {
106            http::StatusCode::OK => ErrorCodes::Success,
107            http::StatusCode::BAD_REQUEST => ErrorCodes::InvalidArgument,
108            http::StatusCode::UNAUTHORIZED => ErrorCodes::Unauthenticated,
109            http::StatusCode::FORBIDDEN => ErrorCodes::PermissionDenied,
110            http::StatusCode::NOT_FOUND => ErrorCodes::NotFound,
111            http::StatusCode::CONFLICT => ErrorCodes::AlreadyExists,
112            http::StatusCode::TOO_MANY_REQUESTS => ErrorCodes::ResourceExhausted,
113            http::StatusCode::INTERNAL_SERVER_ERROR => ErrorCodes::Internal,
114            http::StatusCode::SERVICE_UNAVAILABLE => ErrorCodes::Unavailable,
115            http::StatusCode::NOT_IMPLEMENTED => ErrorCodes::Unimplemented,
116            http::StatusCode::GATEWAY_TIMEOUT => ErrorCodes::DeadlineExceeded,
117            http::StatusCode::PRECONDITION_FAILED => ErrorCodes::FailedPrecondition,
118            http::StatusCode::UNPROCESSABLE_ENTITY => ErrorCodes::UnprocessableEntity,
119            _ => ErrorCodes::Unknown,
120        }
121    }
122}
123
124pub trait ChromaError: Error + Send {
125    fn code(&self) -> ErrorCodes;
126    fn boxed(self) -> Box<dyn ChromaError>
127    where
128        Self: Sized + 'static,
129    {
130        Box::new(self)
131    }
132    fn should_trace_error(&self) -> bool {
133        true
134    }
135}
136
137impl Error for Box<dyn ChromaError> {}
138
139impl ChromaError for Box<dyn ChromaError> {
140    fn code(&self) -> ErrorCodes {
141        self.as_ref().code()
142    }
143}
144
145impl ChromaError for std::io::Error {
146    fn code(&self) -> ErrorCodes {
147        ErrorCodes::Unknown
148    }
149}