Skip to content

fix(router): await server$ stream close so a client disconnect can't crash Bun#8798

Open
aggyomfg wants to merge 2 commits into
QwikDev:build/v2from
aggyomfg:fix/v2-server-function-stream-close
Open

fix(router): await server$ stream close so a client disconnect can't crash Bun#8798
aggyomfg wants to merge 2 commits into
QwikDev:build/v2from
aggyomfg:fix/v2-server-function-stream-close

Conversation

@aggyomfg

@aggyomfg aggyomfg commented Jul 4, 2026

Copy link
Copy Markdown

What is it?

  • Bug

Description

A streaming server$ (an async function* consumed as a stream) crashes the
entire Bun process when the client disconnects mid-stream (SPA navigation
away, tab close, refresh, network drop).

When the client goes away, the response writable is errored, so write/close
reject. The async-iterator branch of runServerFunction called stream.close()
without awaiting or catching it, so the rejection went unhandled. On Bun the
default unhandledRejection behavior is to abort the process (Node only logs a
warning, which is why this stayed hidden there). After the crash every following
request fails with ECONNREFUSED — the server is gone.

The fix extracts the streaming branch into streamServerFunctionResult and
awaits + swallows both the per-item write and the final close, so a
disconnected writable tears down quietly instead of leaking a rejection.

Reproduction: a streaming server$ on the Bun adapter — open the stream,
read one chunk, then abort the request while it is still producing; the process
exits.

Related: #5929 (fixed the TextEncoderStream polyfill, not this close),
#4381 (Node ERR_STREAM_DESTROYED on the same class of teardown),
oven-sh/bun#18228 (Bun's stance: the framework must catch the close).

Test drives streamServerFunctionResult with a writable whose close() rejects (the
post-disconnect state) and asserts no unhandled rejection escapes. It is red
without the fix (leaks Cannot close a writable stream that is closed or errored) and green with it. The process-abort half is Bun-specific and can't be
reproduced under Node, but the leaked-rejection root cause is covered here.

Checklist

  • My code follows the developer guidelines of this project
  • I performed a self-review of my own code
  • I added a changeset with pnpm change
  • I added new tests to cover the fix / functionality

@aggyomfg aggyomfg requested a review from a team as a code owner July 4, 2026 08:42
@changeset-bot

changeset-bot Bot commented Jul 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 40d2fc2

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

This PR includes changesets to release 5 packages
Name Type
@qwik.dev/router Patch
eslint-plugin-qwik Patch
@qwik.dev/core Patch
create-qwik Patch
@qwik.dev/react Patch

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

break;
}
// Swallow rejection: writable may be errored by a client disconnect.
await stream.write(encoder.encode(`${message}\n`)).catch(() => {});

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.

Could we log the error message in dev mode at least?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added dev-logs.

}
}

// Streams an async-iterator server function result to the response writable. A mid-stream

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.

Please remove this comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

removed.

@pkg-pr-new

pkg-pr-new Bot commented Jul 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

@qwik.dev/core

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@8798

@qwik.dev/router

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/router@8798

eslint-plugin-qwik

npm i https://pkg.pr.new/QwikDev/qwik/eslint-plugin-qwik@8798

create-qwik

npm i https://pkg.pr.new/QwikDev/qwik/create-qwik@8798

@qwik.dev/optimizer

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/optimizer@8798

@qwik.dev/devtools

npm i https://pkg.pr.new/QwikDev/qwik/@qwik.dev/devtools@8798

commit: e1e247c

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
qwik-docs ✅ Ready (View Log) Visit Preview e1e247c

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.

2 participants