edge_completions/
error.rs1use std::time::Duration;
2
3use reqwest::StatusCode;
4
5#[derive(Debug, thiserror::Error)]
7#[non_exhaustive]
8pub enum Error {
9 #[error(transparent)]
11 InvalidConfiguration(#[from] InvalidConfiguration),
12
13 #[error("provider request failed before receiving a complete response: {source}")]
15 Transport {
16 #[source]
18 source: reqwest::Error,
19 },
20
21 #[error("provider request timed out after {duration:?}")]
23 Timeout {
24 duration: Duration,
26 #[source]
28 source: reqwest::Error,
29 },
30
31 #[error("provider returned HTTP {status}: {failure}")]
33 Provider {
34 status: StatusCode,
36 failure: ProviderFailure,
38 },
39
40 #[error("provider returned an invalid chat-completion response: {source}")]
42 InvalidResponse {
43 #[source]
45 source: serde_json::Error,
46 },
47
48 #[error("provider response exceeded the configured {limit_bytes}-byte limit")]
50 ResponseTooLarge {
51 limit_bytes: usize,
53 },
54
55 #[error("provider returned a chat completion without any choices")]
57 MissingChoice,
58
59 #[error("provider returned a tool-call completion without a tool call")]
61 MissingToolCall,
62
63 #[error("provider returned a final completion without text content")]
65 MissingContent,
66
67 #[error(transparent)]
69 Tool(#[from] ToolError),
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct ProviderErrorCode(u64);
75
76impl ProviderErrorCode {
77 pub(crate) fn new(value: u64) -> Self {
78 Self(value)
79 }
80
81 #[must_use]
83 pub fn value(self) -> u64 {
84 self.0
85 }
86}
87
88impl std::fmt::Display for ProviderErrorCode {
89 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 self.0.fmt(formatter)
91 }
92}
93
94#[derive(Debug, thiserror::Error)]
96#[non_exhaustive]
97pub enum ProviderFailure {
98 #[error("{message} (provider code {code})")]
100 Coded {
101 code: ProviderErrorCode,
103 message: String,
105 },
106 #[error("{message}")]
108 Message {
109 message: String,
111 },
112 #[error("provider returned an unrecognized error response")]
114 Unrecognized,
115}
116
117#[derive(Debug, Clone, PartialEq, thiserror::Error)]
119#[non_exhaustive]
120pub enum InvalidConfiguration {
121 #[error("required environment variable {name} is missing or is not valid Unicode")]
123 MissingEnvironmentVariable {
124 name: &'static str,
126 },
127 #[error("Cloudflare account ID must not be empty")]
129 EmptyAccountId,
130 #[error("Cloudflare API token must not be empty")]
132 EmptyApiToken,
133 #[error("model ID must not be empty")]
135 EmptyModelId,
136 #[error("chat request must contain at least one message")]
138 EmptyMessages,
139 #[error("a tool-enabled request must contain at least one tool definition")]
141 EmptyTools,
142 #[error("temperature must be finite and between 0 and 2 inclusive, got {value}")]
144 InvalidTemperature {
145 value: f32,
147 },
148 #[error("maximum token count must be greater than zero")]
150 ZeroMaxTokens,
151 #[error("request timeout must be greater than zero")]
153 ZeroTimeout,
154 #[error("response-body byte limit must be greater than zero")]
156 ZeroResponseSizeLimit,
157 #[error("Cloudflare AI Gateway ID is not a valid HTTP header value")]
159 InvalidGatewayId,
160 #[error("provider API base URL is invalid: {reason}")]
162 InvalidBaseUrl {
163 reason: String,
165 },
166 #[error("provider API base URL must use HTTPS unless it points to a loopback host")]
168 InsecureBaseUrl,
169}
170
171#[derive(Debug, thiserror::Error)]
173#[non_exhaustive]
174pub enum ToolError {
175 #[error("tool definition field {field} must not be empty")]
177 InvalidDefinition {
178 field: &'static str,
180 },
181
182 #[error("expected tool {expected}, but the model requested {actual}")]
184 UnexpectedName {
185 expected: &'static str,
187 actual: String,
189 },
190
191 #[error("tool {tool} returned invalid arguments: {source}")]
193 InvalidArguments {
194 tool: String,
196 #[source]
198 source: serde_json::Error,
199 },
200
201 #[error("failed to encode the typed result for tool {tool}: {source}")]
203 ResultEncoding {
204 tool: String,
206 #[source]
208 source: serde_json::Error,
209 },
210}