zilliz 1.2.1

TUI and CLI tool for managing Zilliz Cloud clusters and Milvus operations
Documentation
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 configure` or set ZILLIZ_API_KEY.")]
    NoApiKey,
}

impl ApiError {
    pub fn api(code: i64, mut message: String) -> Self {
        // Enhance error messages like the Python CLI does
        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.",
            );
        }

        // Add error hint if available
        if let Some(hint) = crate::cli::error_hints::get_error_hint(None, code, &message) {
            message.push_str(&format!("\nHint: {}", hint));
        }

        Self::Api { code, message }
    }

    /// Server returned a non-JSON response (HTML error page, etc.)
    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 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,
        }
    }
}