aptu_core/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Error types for the Aptu CLI.
4//!
5//! Uses `thiserror` for deriving `std::error::Error` implementations.
6//! Application code should use `anyhow::Result` for top-level error handling.
7
8use thiserror::Error;
9
10/// Errors that can occur during Aptu operations.
11#[derive(Error, Debug)]
12pub enum AptuError {
13    /// GitHub API error from octocrab.
14    #[error("GitHub API error: {message}")]
15    GitHub {
16        /// Error message.
17        message: String,
18    },
19
20    /// AI provider error (`OpenRouter`, Ollama, etc.).
21    #[error("AI provider error: {message}")]
22    AI {
23        /// Error message from the AI provider.
24        message: String,
25        /// Optional HTTP status code from the provider.
26        status: Option<u16>,
27    },
28
29    /// User is not authenticated - needs to run `aptu auth login`.
30    #[error(
31        "Authentication required - run `aptu auth login` first, or set GITHUB_TOKEN environment variable"
32    )]
33    NotAuthenticated,
34
35    /// Rate limit exceeded from an AI provider.
36    #[error("Rate limit exceeded on {provider}, retry after {retry_after}s")]
37    RateLimited {
38        /// Name of the provider that rate limited (e.g., `OpenRouter`).
39        provider: String,
40        /// Number of seconds to wait before retrying.
41        retry_after: u64,
42    },
43
44    /// Configuration file error.
45    #[error("Configuration error: {message}")]
46    Config {
47        /// Error message.
48        message: String,
49    },
50
51    /// Invalid JSON response from AI provider.
52    #[error("Invalid JSON response from AI")]
53    InvalidAIResponse(#[source] serde_json::Error),
54
55    /// Network/HTTP error from reqwest.
56    #[error("Network error: {0}")]
57    Network(#[from] reqwest::Error),
58
59    /// Keyring/credential storage error.
60    #[cfg(feature = "keyring")]
61    #[error("Keyring error: {0}")]
62    Keyring(#[from] keyring::Error),
63
64    /// Circuit breaker is open - AI provider is unavailable.
65    #[error("Circuit breaker is open - AI provider is temporarily unavailable")]
66    CircuitOpen,
67}
68
69impl From<octocrab::Error> for AptuError {
70    fn from(err: octocrab::Error) -> Self {
71        AptuError::GitHub {
72            message: err.to_string(),
73        }
74    }
75}
76
77impl From<config::ConfigError> for AptuError {
78    fn from(err: config::ConfigError) -> Self {
79        AptuError::Config {
80            message: err.to_string(),
81        }
82    }
83}