Skip to content

fix(node): preserve AsyncLocalStorage context in stream.finished callback#32389

Merged
bartlomieju merged 2 commits intodenoland:mainfrom
bartlomieju:fix/async-local-storage-stream-finished
Mar 2, 2026
Merged

fix(node): preserve AsyncLocalStorage context in stream.finished callback#32389
bartlomieju merged 2 commits intodenoland:mainfrom
bartlomieju:fix/async-local-storage-stream-finished

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

Summary

  • Snapshots the async context when eos() (the implementation behind stream.finished) is called and restores it around the callback invocation
  • In Node.js this context propagation happens automatically through the native AsyncWrap/InternalCallbackScope C++ layer (src/api/callback.cc), but Deno's ops don't flow through that path, so AsyncLocalStorage.getStore() returned undefined inside stream.finished callbacks
  • Adds a unit test verifying the fix with an HTTP server scenario matching the issue reproduction

Closes #32327

Test plan

  • Added asyncLocalStoragePreservedInStreamFinished unit test in tests/unit_node/async_hooks_test.ts
  • Verified the exact PoC from the issue now prints OK: got expected value
  • Existing unit_node::async_hooks_test suite passes

🤖 Generated with Claude Code

…callback

Snapshot the async context when `eos()` is called and restore it around
the callback invocation so that `AsyncLocalStorage.getStore()` returns the
expected value inside `stream.finished` callbacks.

Node.js propagates async context automatically through its native
`AsyncWrap`/`InternalCallbackScope` C++ layer, but Deno's ops don't flow
through that path, so the context was lost by the time the stream emitted
`close`/`finish`/`end`.

Closes denoland#32327

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
// layer, but Deno's ops don't propagate Node-style async context.
const snapshot = core.getAsyncContext();
const originalCallback = callback;
callback = function (...args) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

smart

@bartlomieju bartlomieju enabled auto-merge (squash) March 2, 2026 10:08
@bartlomieju bartlomieju merged commit 63ff522 into denoland:main Mar 2, 2026
112 checks passed
@bartlomieju bartlomieju deleted the fix/async-local-storage-stream-finished branch March 2, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AsyncLocalStorage context is not preserved inside stream.finished callback

2 participants