Skip to main content

token_count/
error.rs

1//! Error types for token counting operations
2
3use thiserror::Error;
4
5/// Errors that can occur during token counting
6#[derive(Error, Debug)]
7pub enum TokenError {
8    #[error("Input contains invalid UTF-8 at byte {offset}")]
9    InvalidUtf8 { offset: usize },
10
11    #[error("Unknown model: '{model}'. {suggestion}")]
12    UnknownModel { model: String, suggestion: String },
13
14    #[error("Input size ({size} bytes) exceeds maximum limit ({limit} bytes). Consider processing in smaller chunks.")]
15    InputTooLarge { size: usize, limit: usize },
16
17    #[error("IO error: {0}")]
18    Io(#[from] std::io::Error),
19
20    #[error("Tokenization error: {0}")]
21    Tokenization(String),
22
23    /// API key not found in environment
24    #[error(
25        "Accurate mode requires ANTHROPIC_API_KEY environment variable.\n\n\
26         Get your API key from: https://console.anthropic.com/\n\
27         Then set: export ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n\
28         For offline estimation (no API key needed), omit --accurate flag:\n  \
29         token-count --model {model}"
30    )]
31    MissingApiKey { model: String },
32
33    /// Invalid API key (401 response)
34    #[error(
35        "Invalid ANTHROPIC_API_KEY. Please check your API key.\n\n\
36         Get a valid key from: https://console.anthropic.com/"
37    )]
38    InvalidApiKey,
39
40    /// Rate limit exceeded (429 response)
41    #[error(
42        "Anthropic API rate limit exceeded. Please try again later.\n\n\
43         Rate limits: https://docs.anthropic.com/en/api/rate-limits"
44    )]
45    RateLimited,
46
47    /// API server error (5xx response)
48    #[error(
49        "Anthropic API server error (HTTP {0}). The service may be temporarily unavailable.\n\n\
50         Check status: https://status.anthropic.com/"
51    )]
52    ApiServerError(u16),
53
54    /// Generic API error
55    #[error("Anthropic API error: {0}")]
56    ApiError(String),
57
58    /// Non-interactive mode without --yes flag
59    #[error(
60        "API call requires consent. Running in non-interactive mode (stdin not a TTY).\n\n\
61         Options:\n  \
62         1. Add -y/--yes flag to skip prompt:\n     \
63            cat file.txt | token-count --model {model} --accurate -y\n  \n  \
64         2. Use estimation mode (no API call):\n     \
65            cat file.txt | token-count --model {model}"
66    )]
67    NonInteractiveWithoutYes { model: String },
68}
69
70impl TokenError {
71    /// Get the exit code for this error
72    pub fn exit_code(&self) -> i32 {
73        match self {
74            Self::InvalidUtf8 { .. } => 1,
75            Self::UnknownModel { .. } => 2,
76            Self::InputTooLarge { .. } => 1,
77            Self::Io(_) => 1,
78            Self::Tokenization(_) => 1,
79            Self::MissingApiKey { .. } => 1,
80            Self::InvalidApiKey => 1,
81            Self::RateLimited => 1,
82            Self::ApiServerError(_) => 1,
83            Self::ApiError(_) => 1,
84            Self::NonInteractiveWithoutYes { .. } => 1,
85        }
86    }
87}