Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/workers-ai-3021-retryable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@cloudflare/gateway-core": patch
"workers-ai-provider": patch
---

Map Workers AI binding error `3021` (inference per-minute rate limit) to HTTP 429 so SDK retries treat it as retryable, matching gateway responses.
1 change: 1 addition & 0 deletions packages/gateway-core/src/workers-ai-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const WORKERS_AI_ERROR_CODE_TO_STATUS: Record<number, number> = {
3008: 408, // Aborted
3036: 429, // Account limited (daily free allocation used up)
3040: 429, // Out of capacity (no data center to forward to)
3021: 429, // Inference request per-minute rate limit reached
};

/** Read a human-readable message from any thrown value (Error, DOMException, plain object, string). */
Expand Down
13 changes: 13 additions & 0 deletions packages/workers-ai-provider/test/workersai-error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ describe("normalizeBindingError", () => {
expect(api.data).toEqual({ workersAIErrorCode: 3040 });
});

it("maps an inference RPM limit (3021) binding error to a retryable 429 APICallError", () => {
const err = normalizeBindingError(
new Error("3021: rate limiting: inference request per min rate reached"),
ctx,
);
expect(APICallError.isInstance(err)).toBe(true);
const api = err as APICallError;
expect(api.statusCode).toBe(429);
expect(api.isRetryable).toBe(true);
expect(api.data).toEqual({ workersAIErrorCode: 3021 });
});

it("maps a client error (5007) to a non-retryable 400 APICallError", () => {
const err = normalizeBindingError(new Error("5007: No such model"), ctx) as APICallError;
expect(APICallError.isInstance(err)).toBe(true);
Expand Down Expand Up @@ -139,6 +151,7 @@ describe("WORKERS_AI_ERROR_CODE_TO_STATUS", () => {
it("maps the documented transient codes to retryable statuses", () => {
expect(WORKERS_AI_ERROR_CODE_TO_STATUS[3040]).toBe(429);
expect(WORKERS_AI_ERROR_CODE_TO_STATUS[3036]).toBe(429);
expect(WORKERS_AI_ERROR_CODE_TO_STATUS[3021]).toBe(429);
expect(WORKERS_AI_ERROR_CODE_TO_STATUS[3007]).toBe(408);
});
});