Skip to content

Core: Handle WebSocket errors so a bad frame can't crash the dev server - #35863

Merged
ghengeveld merged 1 commit into
storybookjs:nextfrom
SnowingFox:fix/35862-server-channel-error-handler
Oct 14, 2026
Merged

ghengeveld merged 1 commit into
storybookjs:nextfrom
SnowingFox:fix/35862-server-channel-error-handler

Conversation

@SnowingFox

@SnowingFox SnowingFox commented Aug 12, 2026 •

Copy link
Copy Markdown

Fixes #35862

What

When a connected browser tab sends a frame exceeding the ws default maxPayload (100 MB) — or any otherwise malformed frame — ws emits an error event on that socket (e.g. WS_ERR_UNSUPPORTED_MESSAGE_LENGTH). The server channel transport in code/core/src/core-server/utils/get-server-channel.ts only attaches a message listener inside the connection handler. In Node.js an error event with no listener is fatal, so a single bad frame from one stale/buggy browser tab crashes the entire storybook dev process.

Fix

Attach an error listener on each server-channel socket that logs the error via the already-imported logger and does not rethrow. ws still closes the offending socket itself, so the dev server keeps running.

Test

Added a regression test in server-channel.test.ts that connects a mock socket and emits an error event on it, asserting it does not throw. Without the fix, EventEmitter throws an unhandled error (the exact process-crash behaviour reported); with the fix, the error is handled and the test passes.

Manual testing

  1. Start storybook dev and open the preview in a browser.
  2. From a connected tab, send an oversized or malformed WebSocket frame (e.g. a message exceeding the ws default maxPayload of 100 MB).
  3. Without this fix the storybook dev process crashes on the unhandled socket error; with this fix the error is logged and the dev server keeps running.

Note: this is a one-handler fix verified against the current next source; the full server-channel.test.ts suite will run on CI here.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4262b918-9920-42f9-9cee-214836804290
📥 Commits

Reviewing files that changed from the base of the PR and between 9c7afb2 and e0b4846.

📒 Files selected for processing: 2
  • code/core/src/core-server/utils/__tests__/server-channel.test.ts
  • code/core/src/core-server/utils/get-server-channel.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

The server channel now attaches an error listener to each connected WebSocket and logs emitted errors. A regression test checks that emitting a socket error does not throw.

Changes

Server-channel WebSocket error handling

Layer / File(s) Summary
Per-socket error handling and regression coverage
code/core/src/core-server/utils/get-server-channel.ts, code/core/src/core-server/utils/__tests__/server-channel.test.ts
The transport logs errors emitted by connected WebSockets. The test verifies that emitting a socket error does not throw.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to e0b48

The new listener logs malformed-frame errors while the affected connection closes normally. No actionable merge risk remains.

Security architecture risk: 🔵 Low · up to 9c7af

The change is narrowly scoped and improves handling of connection errors without changing authentication, message formats or deployment behavior. No introduced security vulnerability was established, but real malformed-frame handling and failures within logging are not fully verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The relevant availability boundary is the shared development-server process and its connected channel clients. The handler changes error processing within an existing connection; the comparison establishes no new cross-service authority or independently exposed endpoint.

Trust Boundaries and Controls

  • observed — Before upgrade, the existing path check, conditional Origin validation and token validation remain in place. The existing skipValidation option still bypasses the latter checks. The new listener is installed after accepted upgrade dispatch and does not alter these admission rules or grant additional privileges.

Resilience and Maintainability Implications

  • observed — The warning path has no visible exception boundary and retains log entries until an explicit clear or successful file write. These logging behaviors predate the PR, and upgrade exceptions already reach the same warning path. No attacker-triggerable logging exception or materially worsened logging exposure was established.

Hardening Proposals

  • proposed — Consider bounded or sampled protocol-error diagnostics and best-effort logging so diagnostic work cannot undermine connection-level failure containment. This is optional hardening, not an observed vulnerability introduced by the PR.
✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/core/src/core-server/utils/__tests__/server-channel.test.ts`:
- Around line 371-381: Update the test around ServerChannelTransport to release
the transport after asserting the socket error behavior. Emit the transport
socket’s close event during cleanup so the real setInterval started by
ServerChannelTransport is cleared, without adding fake-timer setup.
🪄 Autofix

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cf4ce7a7-c264-4124-9d80-e55c6a476a4f

📥 Commits

Reviewing files that changed from the base of the PR and between 4b8bfc7 and 512cab7.

📒 Files selected for processing (2)
  • code/core/src/core-server/utils/__tests__/server-channel.test.ts
  • code/core/src/core-server/utils/get-server-channel.ts

Comment thread code/core/src/core-server/utils/__tests__/server-channel.test.ts Outdated
@SnowingFox SnowingFox changed the title Core-Server: handle server-channel WebSocket errors so a bad frame can't crash the dev server Core-Server: Handle server-channel WebSocket errors so a bad frame can't crash the dev server Aug 12, 2026
@valentinpalkovic valentinpalkovic added bug core sev:S3 Medium priority. Fix within months if possible. labels Aug 12, 2026
@github-actions github-actions Bot added the Stale label Aug 26, 2026
@valentinpalkovic valentinpalkovic added sev:S1 Urgent. Must be fixed within days. and removed sev:S3 Medium priority. Fix within months if possible. labels Sep 11, 2026
@github-actions github-actions Bot added the Stale label Sep 24, 2026
@ghengeveld ghengeveld self-assigned this Oct 5, 2026
@ghengeveld
ghengeveld force-pushed the fix/35862-server-channel-error-handler branch from 512cab7 to 9c7afb2 Compare October 5, 2026 07:05
@ghengeveld ghengeveld added ci:normal Run our default set of CI jobs (choose this for most PRs). and removed needs triage Stale labels Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Fork-based autofix is unavailable. Re-run autofix from a branch in the upstream repository.

@ghengeveld ghengeveld changed the title Core-Server: Handle server-channel WebSocket errors so a bad frame can't crash the dev server Core: Handle WebSocket errors so a bad frame can't crash the dev server Oct 5, 2026
@Sidnioulz Sidnioulz assigned Sidnioulz and unassigned ghengeveld Oct 14, 2026
…n't crash the dev server

When a connected browser tab sends a frame exceeding the ws default maxPayload
(100 MB) — or any malformed frame — ws emits an 'error' event on that socket
(e.g. WS_ERR_UNSUPPORTED_MESSAGE_LENGTH). The server channel transport only
attaches a 'message' listener in the connection handler; in Node an 'error'
event with no listener is fatal, so a single bad frame from one stale browser
tab crashes the whole storybook dev process.

Attach an error listener on each server-channel socket that logs via the
already-imported logger and does not rethrow; ws still closes the offending
socket itself.

Fixes storybookjs#35862

Signed-off-by: liumengjie.ai <liumengjie.ai@bytedance.com>
@ghengeveld
ghengeveld force-pushed the fix/35862-server-channel-error-handler branch from 9c7afb2 to e0b4846 Compare October 14, 2026 10:08
@ghengeveld
ghengeveld enabled auto-merge October 14, 2026 10:10
@ghengeveld ghengeveld added the qa:skip Pull Requests that do not need any QA. (e.g. documentation) label Oct 14, 2026
@ghengeveld
ghengeveld disabled auto-merge October 14, 2026 11:05
@ghengeveld
ghengeveld merged commit 7979fe5 into storybookjs:next Oct 14, 2026
143 of 145 checks passed
@github-actions github-actions Bot mentioned this pull request Oct 14, 2026
2 tasks done
ghengeveld added a commit to storybookjs/sandboxes that referenced this pull request Oct 14, 2026
Check the diff here: storybookjs/storybook@8af3851...50a8282

List of included PRs since previous version:
- storybookjs/storybook#36301 (sharadvc/cursor/fix-mcp-connect-agents-link-6fef)
- storybookjs/storybook#35863 (SnowingFox/fix/35862-server-channel-error-handler)
- storybookjs/storybook#36688 (ghengeveld/vitest-36221-leftovers)
- storybookjs/storybook#36746 (fix/bbc-local-story-manifest-snippets)
- storybookjs/storybook#36588 (fix/nextjs-router-mock-bfcache)
- storybookjs/storybook#36391 (agent/sto-492-eslint-cjs)
- storybookjs/storybook#36751 (agent/sto-280-prerelease-version-alignment)
- storybookjs/storybook#36768 (svelte-knip-cleanup)
- storybookjs/storybook#35834 (FrancoKaddour/fix/docgen-typescript7-missing-compiler-api)
- storybookjs/storybook#36770 (bryce-easygo/fix/svelte-csf-null-arg-snippet)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-scan:automated bug ci:normal Run our default set of CI jobs (choose this for most PRs). core qa:skip Pull Requests that do not need any QA. (e.g. documentation) sev:S1 Urgent. Must be fixed within days.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: Server channel WebSocket error crashes the entire Storybook process (WS_ERR_UNSUPPORTED_MESSAGE_LENGTH)

4 participants