use thiserror::Error;
#[derive(Debug, Error)]
pub enum ApiError {
#[error("{message}")]
Api { code: i64, message: String },
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("Invalid JSON response: {0}")]
InvalidJson(String),
#[error(
"Authentication required. Run `zilliz login` (or `zilliz configure` / set ZILLIZ_API_KEY)."
)]
NoApiKey,
}
impl ApiError {
pub fn api(code: i64, mut message: String) -> Self {
let is_permission_denied = message.contains("PermissionDenied")
|| message.to_lowercase().contains("permission deny");
if is_permission_denied {
message.push_str(
"\n\nThis may be a cluster plan restriction. \
Some operations (user/role management, multi-database) \
are only available on Dedicated clusters.",
);
}
if let Some(hint) = crate::cli::error_hints::get_error_hint(None, code, &message) {
message.push_str(&format!("\nHint: {}", hint));
}
Self::Api { code, message }
}
pub fn non_json_response(status: reqwest::StatusCode, content_type: &str) -> Self {
let hint = match status.as_u16() {
401 | 403 => {
"Invalid or expired API key. Run `zilliz login` (or `zilliz configure`) to update."
}
404 => "API endpoint not found. Check your cluster endpoint.",
502..=504 => "Service temporarily unavailable. Try again later.",
_ => "Server returned a non-JSON response.",
};
let mut message = format!("HTTP {} ({}). {}", status.as_u16(), content_type, hint);
if let Some(extra_hint) =
crate::cli::error_hints::get_error_hint(Some(status.as_u16()), 0, &message)
{
message.push_str(&format!("\nHint: {}", extra_hint));
}
Self::Api {
code: status.as_u16() as i64,
message,
}
}
}