1use thiserror::Error;
2
3#[derive(Debug, Error)]
5pub enum HsPredictError {
6 #[error("Invalid HS code format: '{0}' (expected 6-digit number, e.g. \"281511\")")]
8 InvalidHsCode(String),
9
10 #[error("Invalid CAS number format: '{0}' (expected digits-digits-digit, e.g. \"1310-73-2\")")]
11 InvalidCasNumber(String),
12
13 #[error("At least one identifier (cas, smiles, iupac_name, or inchi) must be provided")]
14 MissingIdentifier,
15
16 #[error("Mixture component #{index} is missing an identifier")]
17 MissingComponentIdentifier { index: usize },
18
19 #[error("No active question — call start() or answer() first")]
21 NoActiveQuestion,
22
23 #[error("Answer type mismatch: expected {expected}, got {got}")]
24 AnswerTypeMismatch { expected: &'static str, got: &'static str },
25
26 #[error("Choice index {index} out of range (valid range: 0..={max})")]
27 InvalidChoiceIndex { index: usize, max: usize },
28
29 #[error("Number {value} is out of range [{min}, {max}]")]
30 NumberOutOfRange { value: f64, min: f64, max: f64 },
31
32 #[error("Session is already complete — create a new ClassificationSession")]
33 SessionAlreadyComplete,
34
35 #[error(
37 "Confidence {confidence:.2} is below threshold {threshold:.2} \
38 and no LLM client is configured"
39 )]
40 LowConfidenceNoLlm { confidence: f32, threshold: f32 },
41
42 #[error("Mixture classification depth limit exceeded (max 2 levels)")]
43 MixtureDepthExceeded,
44
45 #[error(
47 "LLM client is not configured. \
48 Enable the `llm` feature and supply an API key."
49 )]
50 LlmNotConfigured,
51
52 #[error("LLM API error {status_code}: {message}")]
53 LlmApiError { status_code: u16, message: String },
54
55 #[error("Failed to parse LLM response as JSON: {source}\nRaw response: {raw}")]
56 LlmResponseParseError {
57 #[source]
58 source: serde_json::Error,
59 raw: String,
60 },
61
62 #[error("LLM rate limit exceeded — retry after {retry_after_secs}s")]
63 LlmRateLimitError { retry_after_secs: u64 },
64
65 #[error("LLM returned '{code}': not a valid 6-digit HS 2022 code")]
67 ValidationFailed { code: String },
68
69 #[error(
70 "LLM code '{llm_code}' conflicts with rule-engine chapter '{expected_chapter}'"
71 )]
72 ChapterConflict { llm_code: String, expected_chapter: String },
73
74 #[cfg(feature = "pubchem")]
76 #[error("PubChem error: {0}")]
77 PubChem(#[from] crate::pubchem::PubChemError),
78
79 #[error("Serialization error: {0}")]
81 Serialization(#[from] serde_json::Error),
82
83 #[error("HTTP error: {0}")]
84 Http(String),
85}
86
87pub type Result<T> = std::result::Result<T, HsPredictError>;