fix: serialize parallel test results without mutating user objects#6056
Draft
GrahamCampbell wants to merge 2 commits into
Draft
fix: serialize parallel test results without mutating user objects#6056GrahamCampbell wants to merge 2 commits into
GrahamCampbell wants to merge 2 commits into
Conversation
Contributor
|
👋 Hi @GrahamCampbell, thanks for the pull request! A scan flagged a concern with it. Could you please take a look? [pr-task-completion] This PR's body is missing
Repositories often provide a set of tasks that pull request authors are expected to complete. Those tasks should be marked as completed with a
|
3 tasks
Member
|
Marking as draft until the backing issue it out of triage :) |
mark-wiemer
marked this pull request as draft
June 11, 2026 01:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Checklist
status: accepting prsOverview
In parallel mode,
SerializableEvent#serializeprepares events for IPC by walking the event'sdataanderrorgraphs in place: function-valued properties aredeleted from the original objects. When a failing test's error references shared state (the #6053 repro reachesrequire('crypto')), shared modules are permanently stripped of their functions for later files run by the reused worker, and when the walk reaches a non-configurable property (e.g. thecrypto.getRandomValuesaccessor) the strict-modedeletethrows, abortingSerializableWorkerResult#serialize— the whole file's result batch is lost and the original failure is never reported.This PR replaces the in-place walk with one that builds a fresh, JSON-safe copy and never mutates its inputs:
[Circular]marker into the copy). ThebreakCircularDeps(result.error)call is removed: it mutated original error graphs, and it crashes outright on ESM module namespace objects (TypeError: Cannot assign to read only property ... of '[object Module]'— namespace exports reportwritable: truebut reject[[Set]]), theimport *twin of the reported bug. The exported util itself is untouched.dataorerror, pre-seeded by the top-level keys) and doubled as the walk's only termination guard — is replaced by identity-based cycle detection plus a node budget and depth cap ([Truncated]placeholder). Cyclic event data previously survived the walk and killed the batch inprocess.send; lazily-infinite getter chains could hang the worker.[element, index]pairs (element as the parent), so e.g. the extra errors inerr.multiplecrossed the wire as{}with their messages lost. Function elements becomenull, which is what the JSON IPC channel already did to leaked functions.BigIntvalues are stringified (previously a guaranteedprocess.sendTypeError losing the batch) and throwing getters are omitted rather than fatal.error.cause(own but non-enumerable, previously dropped by theObject.assigncopy) is carried, so cause chains render in parallel mode as they do in serial mode.SerializableWorkerResult#serializenow substitutes a same-eventNamestand-in when an event still cannot be serialized, so a single pathological event cannot erase a file's results.Wire compatibility: all existing serializer unit tests pass unchanged (two test titles reworded, assertions untouched), and the existing parallel integration fixtures for circular references and getters pass as-is. An own enumerable
toJSONis still not honored while inherited implementations (Date,Buffer) still are, matching the previous end-to-end JSON behavior. The deliberate, visible differences are strict improvements over data destruction: nested errors arrive withmessage/stackinstead of{}, data cycles serialize as[Circular]instead of crashing the send, and pathological graphs truncate instead of hanging or overflowing.Verification: 60 serializer unit tests (40 existing + 20 new, one per hazard), the parallel integration specs, and an end-to-end run of the #6053 repro (the original failure is reported and
cryptostays intact in the reused worker) all pass on this branch.Note: the first commit here is the same change as #6055 — on current
mainthe serializer spec cannot load (#6054), so this branch needs it to run its own tests; happy to rebase once #6055 or #6015 lands. The four node-unit failures visible on this branch (buffered-worker-pool,parallel-buffered-runner,reporters/parallel-buffered,mocha.spec) predate it — currentmaincannot run the node-unit suite at all — and are addressed by #6015. A v11.x backport (the serializer there is identical apart from module wrappers) follows separately.