Skip to content

fix(ext/web): allow transferring non-serializable types in structuredClone - #33491

Merged
bartlomieju merged 4 commits into
mainfrom
fix/structuredclone-transfer-not-serializable
Apr 25, 2026
Merged

fix(ext/web): allow transferring non-serializable types in structuredClone#33491
bartlomieju merged 4 commits into
mainfrom
fix/structuredclone-transfer-not-serializable

Conversation

@bartlomieju

Copy link
Copy Markdown
Member

Summary

Fixes a regression from #33465 where structuredClone(value, { transfer: [value] }) threw DataCloneError for ReadableStream, WritableStream, and TransformStream. The kNotSerializable check was firing even when the value was being transferred, not cloned.

The fix skips the check when the value is present in the transfer list.

Test plan

  • ./x test-compat test-webstream-structured-clone-no-leftovers -- now passes
  • ./x test-spec structured_clone_non_serializable -- still passes (cloning without transfer still throws)

…Clone

The kNotSerializable check added in #33465 was too broad -- it threw
DataCloneError even when the value was being transferred, not cloned.
Skip the check when the value is in the transfer list.
@bartlomieju
bartlomieju enabled auto-merge (squash) April 25, 2026 18:15
@bartlomieju
bartlomieju disabled auto-merge April 25, 2026 18:15
@bartlomieju
bartlomieju enabled auto-merge (squash) April 25, 2026 18:15
The "A subclass instance will be received as its closest transferable
superclass" test now passes for both window and worker contexts.

@fibibot fibibot 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.

LGTM. This is the right fix for the regression I flagged on #33482 — the unconditional kNotSerializable check at ext/web/13_message_port.js:561 was firing for structuredClone(stream, { transfer: [stream] }) even though the stream was being transferred, not cloned. Adding && !ArrayPrototypeIncludes(options.transfer, value) skips the check exactly when the user asked for transfer.

Verified:

  • ArrayPrototypeIncludes is already imported on line 18, so no new primordial needed.
  • The check runs after webidl.converters.StructuredSerializeOptions(options, ...), so options.transfer is guaranteed to be an array (defaults to []), and a non-transferable object that gets passed in will still fail downstream at V8's serializer with DataCloneError — same observable behavior, just a different throw site.
  • The two html.json expectations dropped ("A subclass instance will be received as its closest transferable superclass" at lines 994 + 1023) confirm this WPT subcase now passes.
  • Cloning without transfer still throws, since value[kNotSerializable] still gates the path when the transfer list doesn't contain value.

@bartlomieju
bartlomieju merged commit c455ef1 into main Apr 25, 2026
112 checks passed
@bartlomieju
bartlomieju deleted the fix/structuredclone-transfer-not-serializable branch April 25, 2026 19:19
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