Skip to content

[vitest-pool-workers] fix: handle redirect responses in runInDurableObject#13077

Merged
penalosa merged 1 commit intomainfrom
penalosa/vitest-9907
Mar 27, 2026
Merged

[vitest-pool-workers] fix: handle redirect responses in runInDurableObject#13077
penalosa merged 1 commit intomainfrom
penalosa/vitest-9907

Conversation

@penalosa
Copy link
Copy Markdown
Contributor

@penalosa penalosa commented Mar 26, 2026

Fixes #9907.

runInDurableObject (and runDurableObjectAlarm) would throw AssertionError: Expected callback for X when the user's callback returned a redirect (3xx) Response. The internal stub.fetch() used the default redirect: "follow" mode, so the runtime would follow the redirect — preserving the cf action ID — and re-enter maybeHandleRunRequest after the callback slot had already been consumed. Adding redirect: "manual" lets the existing kUseResponse path return the redirect as-is.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: bug fix with no user-facing API change

Open with Devin

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 26, 2026

🦋 Changeset detected

Latest commit: c485ee1

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

✅ All changesets look good

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 26, 2026

The change is clean and well-reasoned. Let me verify the fix logic once more by re-reading the maybeHandleRunRequest function to confirm that redirect: "manual" is the correct and complete fix, and that there are no edge cases missed.

The flow is:

  1. runInStub stores a callback in actionResults map with an id, then calls stub.fetch() with that id in cf.
  2. maybeHandleRunRequest picks up the request, runs the callback, and if the result is a Response, sets actionResults[id] = kUseResponse and returns the Response.
  3. Back in runInStub, if result === kUseResponse, it returns the response from stub.fetch() directly.

The bug: Without redirect: "manual", when the callback returns a 3xx Response, the runtime follows the redirect. This redirect preserves the cf property (including the action ID). The redirected request re-enters maybeHandleRunRequest, but by then the callback has already been consumed and replaced with kUseResponse, so typeof callback === "function" fails.

The fix is correct: redirect: "manual" prevents the runtime from following the redirect, so the 3xx Response is returned directly and handled by the kUseResponse path.

The test changes are also sound:

  • New regression test properly validates 302 status and Location header.
  • The listDurableObjectIds assertion change from exact match to toContain is necessary because the new test creates an additional DO instance, so there are now 2 IDs instead of 1.

LGTM

github run

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 26, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@13077

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@13077

miniflare

npm i https://pkg.pr.new/miniflare@13077

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@13077

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@13077

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@13077

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@13077

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@13077

wrangler

npm i https://pkg.pr.new/wrangler@13077

commit: c485ee1

@penalosa penalosa marked this pull request as ready for review March 27, 2026 00:36
@penalosa penalosa requested a review from a team as a code owner March 27, 2026 00:36
@penalosa penalosa force-pushed the penalosa/vitest-9907 branch from e86cda7 to c485ee1 Compare March 27, 2026 00:37
@workers-devprod
Copy link
Copy Markdown
Contributor

workers-devprod commented Mar 27, 2026

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Copy link
Copy Markdown
Member

@dario-piotrowicz dario-piotrowicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-project-automation github-project-automation bot moved this from Untriaged to Approved in workers-sdk Mar 27, 2026
@penalosa penalosa merged commit 11c77b7 into main Mar 27, 2026
50 of 52 checks passed
@penalosa penalosa deleted the penalosa/vitest-9907 branch March 27, 2026 13:22
@github-project-automation github-project-automation bot moved this from Approved to Done in workers-sdk Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Cloudflare Vitest Pool Workers fails to handle 302 redirect responses from Durable Objects with "Expected callback for X" error

3 participants