Commit 3d21dca
committed
Implementing Consistent Error Handling Across Providers
This document provides instructions for implementing consistent error handling across all provider classes in the `src/api/providers/` directory. The goal is to ensure that all providers format errors in a consistent way that can be properly processed by `Cline.ts`.
## Background
The `Cline.ts` component expects errors to be formatted in a specific way to properly handle different error types, especially rate limit errors (429). Currently, only the `vscode-lm.ts` and `anthropic.ts` providers format errors in this way. We need to update all other providers to follow the same pattern.
## Error Format
Errors should be formatted as JSON strings wrapped in Error objects with the following structure:
```javascript
throw new Error(JSON.stringify({
status: 429, // HTTP status code
message: "Rate limit exceeded", // Human-readable message
error: {
metadata: {
raw: errorObj.message || "Too many requests, please try again later"
}
},
errorDetails: [{ // Optional, for rate limit errors
"@type": "type.googleapis.com/google.rpc.RetryInfo",
retryDelay: "30s"
}]
}));
```
## Implementation Steps
For each provider in the `src/api/providers/` directory, follow these steps:
1. **Identify the `createMessage` Method**:
- Locate the `createMessage` method in the provider class.
- This method should be an async generator function that returns an `ApiStream`.
2. **Add Error Handling**:
- Wrap the main logic of the method in a try-catch block.
- In the catch block, implement error handling as shown below.
3. **Format Errors Consistently**:
- Add specific handling for different error types:
- Rate limit errors (429)
- Authentication errors (401)
- Bad request errors (400)
- Other errors (500)
- Return errors as JSON strings in Error objects.
4. **Update Tests**:
- Update the tests for each provider to verify the new error handling.
- Add tests for different error scenarios.
## Error Handling Template
Here's a template for the error handling code to add to each provider:
```typescript
try {
// Existing code for creating and processing the stream
} catch (error) {
// Format errors in a consistent way
console.error("Provider API error:", error);
// Handle rate limit errors specifically
const errorObj = error as any;
if (errorObj.status === 429 ||
(errorObj.message && errorObj.message.toLowerCase().includes('rate limit'))) {
throw new Error(JSON.stringify({
status: 429,
message: "Rate limit exceeded",
error: {
metadata: {
raw: errorObj.message || "Too many requests, please try again later"
}
},
errorDetails: [{
"@type": "type.googleapis.com/google.rpc.RetryInfo",
retryDelay: "30s" // Default retry delay if not provided
}]
}));
}
// Handle authentication errors
if (errorObj.status === 401 ||
(errorObj.message && errorObj.message.toLowerCase().includes('api key'))) {
throw new Error(JSON.stringify({
status: 401,
message: "Authentication error",
error: {
metadata: {
raw: errorObj.message || "Invalid API key or unauthorized access"
}
}
}));
}
// Handle bad request errors
if (errorObj.status === 400 ||
(errorObj.error && errorObj.error.type === "invalid_request_error")) {
throw new Error(JSON.stringify({
status: 400,
message: "Bad request",
error: {
metadata: {
raw: errorObj.message || "Invalid request parameters",
param: errorObj.error?.param
}
}
}));
}
// Handle other errors
if (error instanceof Error) {
throw new Error(JSON.stringify({
status: errorObj.status || 500,
message: error.message,
error: {
metadata: {
raw: error.message
}
}
}));
} else if (typeof error === "object" && error !== null) {
const errorDetails = JSON.stringify(error, null, 2);
throw new Error(JSON.stringify({
status: errorObj.status || 500,
message: errorObj.message || errorDetails,
error: {
metadata: {
raw: errorDetails
}
}
}));
} else {
// Handle primitive errors or other unexpected types
throw new Error(JSON.stringify({
status: 500,
message: String(error),
error: {
metadata: {
raw: String(error)
}
}
}));
}
}
```
## Provider-Specific Considerations
Some providers may have specific error types or patterns that need special handling. Here are some provider-specific considerations:
### OpenAI and OpenAI-Native
- Check for OpenAI-specific error types like `openai.APIError`.
- Look for rate limit indicators in the error response.
### Bedrock
- Bedrock may have AWS-specific error types.
- Look for throttling indicators in the error message.
### Vertex
- Vertex may have Google Cloud-specific error types.
- Check for quota exceeded errors.
### Gemini
- Similar to Vertex, check for Google-specific error patterns.
### Mistral, DeepSeek, Ollama, LMStudio
- These providers may have their own error formats.
- Adapt the error handling to match their specific patterns.
## Testing
For each provider, update or add tests to verify the error handling:
1. **Test Rate Limit Errors**:
- Mock a 429 status code error.
- Verify the error is formatted correctly.
2. **Test Authentication Errors**:
- Mock a 401 status code error.
- Verify the error is formatted correctly.
3. **Test Bad Request Errors**:
- Mock a 400 status code error.
- Verify the error is formatted correctly.
4. **Test Other Errors**:
- Mock a generic error.
- Verify the error is formatted correctly.
## Example Test
Here's an example test for verifying rate limit error handling:
```typescript
it("should handle rate limit errors with proper format", async () => {
mockCreate.mockImplementationOnce(() => {
const error = new Error("Rate limit exceeded");
error.status = 429;
throw error;
});
const stream = handler.createMessage(systemPrompt, messages);
try {
for await (const _ of stream) {
// consume stream
}
fail("Should have thrown an error");
} catch (error) {
expect(error).toBeInstanceOf(Error);
const parsedError = JSON.parse((error as Error).message);
expect(parsedError.status).toBe(429);
expect(parsedError.message).toBe("Rate limit exceeded");
expect(parsedError.errorDetails[0]["@type"]).toBe("type.googleapis.com/google.rpc.RetryInfo");
}
});
```
## Providers to Update
Here's a list of all providers that need to be updated:
1. ✅ `anthropic.ts` (already updated)
2. ✅ `vscode-lm.ts` (already updated)
3. ✅ `openai.ts` (already updated)
4. ✅ `openai-native.ts` (already updated)
5. ✅ `bedrock.ts` (already updated)
6. ✅ `vertex.ts`(already updated)
7. ✅ `gemini.ts`(already updated)
8. ✅ `mistral.ts` (already updated)
9. ✅ `deepseek.ts` (already updated)
10. ✅ `ollama.ts` (already updated)
11. ✅ `lmstudio.ts` (already updated)
12. ✅ `openrouter.ts` (already updated)
13. ✅ `glama.ts`
14. ✅ `unbound.ts`
15. ✅ `requesty.ts`
16. ✅ `human-relay.ts`
17. ✅ `fake-ai.ts`
## Conclusion
By implementing consistent error handling across all providers, we ensure that `Cline.ts` can properly handle errors from any provider, especially rate limit errors. This will improve the user experience by providing better error messages and enabling automatic retries when appropriate.1 parent 5bae398 commit 3d21dca
File tree
26 files changed
+4480
-673
lines changed- src
- api/providers
- __tests__
- core
- __tests__
- webview-ui/src/components/chat
26 files changed
+4480
-673
lines changedLines changed: 370 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
0 commit comments