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 /// Name of the AI provider (e.g., `OpenRouter`, `Ollama`).
28 provider: String,
29 },
30
31 /// User is not authenticated - needs to run `aptu auth login`.
32 #[error(
33 "Authentication required - run `aptu auth login` first, or set GITHUB_TOKEN environment variable"
34 )]
35 NotAuthenticated,
36
37 /// Rate limit exceeded from an AI provider.
38 #[error("Rate limit exceeded on {provider}, retry after {retry_after}s")]
39 RateLimited {
40 /// Name of the provider that rate limited (e.g., `OpenRouter`).
41 provider: String,
42 /// Number of seconds to wait before retrying.
43 retry_after: u64,
44 },
45
46 /// AI response was truncated (incomplete JSON due to EOF).
47 #[error("Truncated response from {provider} - response ended prematurely")]
48 TruncatedResponse {
49 /// Name of the AI provider that returned truncated response.
50 provider: String,
51 },
52
53 /// Configuration file error.
54 #[error("Configuration error: {message}")]
55 Config {
56 /// Error message.
57 message: String,
58 },
59
60 /// Invalid JSON response from AI provider.
61 #[error("Invalid JSON response from AI")]
62 InvalidAIResponse(#[source] serde_json::Error),
63
64 /// Network/HTTP error from reqwest.
65 #[error("Network error: {0}")]
66 Network(#[from] reqwest::Error),
67
68 /// Keyring/credential storage error.
69 #[cfg(feature = "keyring")]
70 #[error("Keyring error: {0}")]
71 Keyring(#[from] keyring::Error),
72
73 /// Circuit breaker is open - AI provider is unavailable.
74 #[error("Circuit breaker is open - AI provider is temporarily unavailable")]
75 CircuitOpen,
76}
77
78impl From<octocrab::Error> for AptuError {
79 fn from(err: octocrab::Error) -> Self {
80 AptuError::GitHub {
81 message: err.to_string(),
82 }
83 }
84}
85
86impl From<config::ConfigError> for AptuError {
87 fn from(err: config::ConfigError) -> Self {
88 AptuError::Config {
89 message: err.to_string(),
90 }
91 }
92}