You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug Report — Runtime APIs - concurrent env.AI.run() calls can return responses in the wrong format #8203
env.AI.run() stores its per-call options in a single shared #options field on the binding instance, and reads that field back after awaiting the upstream fetch to decide the response format. When two run() calls overlap on the same binding, the first call formats its response according to the second call's options.
In src/cloudflare/internal/ai-api.ts (line numbers as of 71cca5873, 2026-11-03):
Each call writes its settings into the shared slot and then waits for the AI service to reply:
this.#options = options; — line 314
res = await this.#generateFetch(…); — line 337 (waits here)
When the reply arrives, it reads the slot again to decide what format to return:
If another call started in the meantime, the slot now holds that other call's settings, so the earlier call returns its reply in the wrong format.
Example interleaving
constrawPromise=env.AI.run('some-model',inputs,{returnRawResponse: true});// while the first call is still in flight, another call starts and finishes:awaitenv.AI.run('other-model',otherInputs);constres=awaitrawPromise;// `res` is a parsed object (or throws), not the Response the caller asked for
Observed consequences in both directions:
a returnRawResponse: true call overlapping with any plain run() call can receive a parsed object instead of a Response, breaking access to res.body (streaming);
a plain call overlapping with a returnRawResponse: true call can receive an unexpected Response.
Note that all other reads of this.#options (extra headers, prefix, signal, and the websocket branch at line 328) happen synchronously before the fetch is started, so the post-await read at line 357 is the only affected spot.
Expected behavior
Each run() call should format its own response according to the options passed to that call, regardless of concurrent calls on the same binding.
Reproduction
Deterministic reproduction requires two overlapping calls on the same binding instance: start a call whose upstream reply is delayed, start a quick returnRawResponse: true call while the first is in flight, then await the first — it resolves with the second call's format instead of its own.
I have a minimal one-line fix (read the call's own options at the format decision) plus regression tests for src/cloudflare/internal/test/ai/ ready and will follow up with a PR referencing this issue.
Environment
workerd main as of 71cca5873 (2026-11-03)
Reproduced by executing src/cloudflare/internal/ai-api.ts with concurrent run() calls against a stubbed fetcher; the bug is in the shared-slot logic itself, independent of runtime version.
changed the title [-]🐛 Bug Report — Runtime APIs - concurrent env.AI.run() calls can return responses in the wrong format[/-][+]Bug Report — Runtime APIs - concurrent env.AI.run() calls can return responses in the wrong format[/+]on Nov 3, 2026
Activity
[-]🐛 Bug Report — Runtime APIs - concurrent env.AI.run() calls can return responses in the wrong format[/-][+]Bug Report — Runtime APIs - concurrent env.AI.run() calls can return responses in the wrong format[/+]