Why a question went unanswered. Every variant that saw a response carries its request id, the only handle for a billing dispute.
The request would break an API rule; nothing was sent.
13 Invalid(ProtocolError),
The API refused, after any retries. The request id is inside.
15 Api { error: ApiError, attempts: u32 },
No usable response. request_id is the last one any earlier
attempt received.
18 Transport { error: TransportError, attempts: u32, request_id: Option<String> },
Every attempt ran out of time, or the budget did.
20 TimedOut { attempts: u32, request_id: Option<String> },
A 200 that does not answer the questions, or answers from another model.
26impl ClientError {
Whether the failed ask certainly cost nothing: it was never sent, or the API refused the one attempt made. Anything else (a retried refusal, a broken exchange, a timeout, an unusable 200) may have been billed, and a budget should count it as spent.
The request id to quote, if any response carried one.
40 pub fn request_id(&self) -> Option<&str> { 41 match self { 42 ClientError::Invalid(_) => None, 43 ClientError::Api { error, .. } => error.request_id.as_deref(), 44 ClientError::Transport { request_id, .. } 45 | ClientError::TimedOut { request_id, .. } 46 | ClientError::Response { request_id, .. } => request_id.as_deref(), 47 } 48 } 49}
51impl fmt::Display for ClientError { 52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 53 let attempts = |n: &u32| if *n == 1 { String::new() } else { format!(" after {n} attempts") }; 54 match self { 55 ClientError::Invalid(e) => write!(f, "{e}"), 56 // ApiError's own Display carries the request id. 57 ClientError::Api { error, attempts: n } => write!(f, "{error}{}", attempts(n)), 58 ClientError::Transport { error, attempts: n, .. } => write!(f, "{error}{}", attempts(n)), 59 ClientError::TimedOut { attempts: n, .. } => write!(f, "Jev did not answer in time{}", attempts(n)), 60 ClientError::Response { error, .. } => write!(f, "{error}"), 61 }?; 62 match self { 63 ClientError::Transport { request_id: Some(id), .. } 64 | ClientError::TimedOut { request_id: Some(id), .. } 65 | ClientError::Response { request_id: Some(id), .. } => write!(f, " [request {id}]"), 66 _ => Ok(()), 67 } 68 } 69} 70 71impl std::error::Error for ClientError {}