use thiserror::Error;
use tonic::codegen::http::uri::InvalidUri;
#[cfg(feature = "serde")]
use crate::serde_deser::DeserPayloadError;
#[derive(Error, Debug)]
pub enum QdrantError {
#[error("Error in the response: {} {} {:?}", .status.code(), .status.message(), .status.metadata())]
ResponseError {
status: tonic::Status,
},
#[error("Resource exhausted: {} {} {:?}, retry after {} seconds", .status.code(), .status.message(), .status.metadata(), .retry_after_seconds)]
ResourceExhaustedError {
status: tonic::Status,
retry_after_seconds: u64,
},
#[error("Error in conversion: {}", .0)]
ConversionError(String),
#[error("Invalid URI: {}", .0)]
InvalidUri(#[source] InvalidUri),
#[error("No snapshot found for collection: {}", .0)]
NoSnapshotFound(String),
#[error("IO error: {}", .0)]
Io(#[from] std::io::Error),
#[cfg(feature = "reqwest")]
#[error("Reqwest error: {}", .0)]
Reqwest(#[from] reqwest::Error),
#[cfg(feature = "serde")]
#[error("JSON cannot be converted to payload, only JSON objects are supported")]
JsonToPayload(serde_json::Value),
#[cfg(feature = "serde")]
#[error("Error in payload deserialization")]
PayloadDeserialization(#[from] DeserPayloadError),
}
impl QdrantError {
#[cfg(feature = "serde")]
#[allow(dead_code)]
pub(crate) fn as_payload_deserialization(&self) -> Option<&DeserPayloadError> {
if let QdrantError::PayloadDeserialization(err) = self {
Some(err)
} else {
None
}
}
}
impl From<tonic::Status> for QdrantError {
fn from(status: tonic::Status) -> Self {
if status.code() == tonic::Code::ResourceExhausted {
if let Some(retry_after_value) = status
.metadata()
.get("retry-after")
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse().ok())
{
return QdrantError::ResourceExhaustedError {
status,
retry_after_seconds: retry_after_value,
};
}
}
QdrantError::ResponseError { status }
}
}
impl From<InvalidUri> for QdrantError {
fn from(err: InvalidUri) -> Self {
QdrantError::InvalidUri(err)
}
}