You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Please consider backporting #64706 (fix for #64061) to the v22.x release line.
State as of 2026-09-09, checked with the GitHub contents API against lib/internal/test_runner/runner.js, looking for ) >>> 0) + kSerializedSizeHeader:
ref
has the fix
main
yes
v26.x
yes
v24.x, v24.x-staging
yes
v22.x, v22.x-staging
no
#64706 carries no dont-land-on-v22.x label, and I could not find an existing backport request or backport PR for v22.x.
The line is actively released — the most recent v22 release is v22.23.2 (2026-07-29), three days after #64706 landed on main (2026-07-26).
Why this may deserve more weight than the original report suggested
#64061 was reported as an intermittent CI flake. On v22.19.0 I traced the trigger, and it turns out not to be exotic: it is ordinary non-ASCII text written to stdout by a test.
FileTest.#processRawBuffer advances bufferHead past a consumed message and then reads the next four bytes as a length without re-checking for the FF 0F header:
bufferHead=TypedArrayPrototypeSubarray(concatenatedBuffer,fullMessageSize);this.#rawBufferSize =TypedArrayPrototypeGetLength(bufferHead);
...
while(bufferHead?.length>=kSerializedSizeHeader){constfullMessageSize=(bufferHead[kV8HeaderLength]<<24|bufferHead[kV8HeaderLength+1]<<16|bufferHead[kV8HeaderLength+2]<<8|bufferHead[kV8HeaderLength+3])+kSerializedSizeHeader;// signed 32-bitif(this.#rawBufferSize <fullMessageSize)break;
When a test's own stdout follows a report message inside the same read, those bytes are interpreted as a length. Every UTF-8 lead/continuation byte is >= 0x80, so any non-ASCII output — CJK, emoji, accented Latin — can make fullMessageSize negative, which defeats the break guard and hands garbage to DefaultDeserializer.
In our repository the emitter was a server start-up banner containing an emoji, printed by the code under test. Three sightings over two days, always the same test file.
Minimal deterministic reproduction
No load, no concurrency, no flakiness. One write():
// repro.mjs — node --test repro.mjsimport{writeSync}from'node:fs';importtestfrom'node:test';import{DefaultSerializer}from'node:v8';test('a passing test',()=>{});consts=newDefaultSerializer();s.writeHeader();s.writeValue({__proto__: null,type: 'test:diagnostic',data: {__proto__: null,nesting: 0,message: 'hi',file: 'repro.mjs'}});constpayload=s.releaseBuffer();constsize=Buffer.alloc(4);size.writeUInt32BE(payload.length);constmessage=Buffer.concat([Buffer.from([0xff,0x0f]),size,payload]);// a report message, immediately followed by ordinary test stdout, in ONE writeconsttail=process.env.ASCII ? '\nserver listening -> http://localhost:3456\n'
: '\n\u{1F7E1} 서버 실행 중 -> http://localhost:3456\n';writeSync(1,Buffer.concat([message,Buffer.from(tail,'utf8')]));
On v22.19.0, Windows 11 x64:
$ node --test repro.mjs
not ok 1 - repro.mjs
error: 'Unable to deserialize cloned data due to invalid or unsupported version.'
# fail 1
$ ASCII=1 node --test repro.mjs
ok 1 - a passing test
# fail 0
The only difference between the two runs is whether the trailing stdout is ASCII.
I only have v22.19.0 on this machine, so I have not run this against a fixed release line — the report above is strictly about v22.19.0.
Three symptoms, and one of them is silent
Also observed on v22.19.0, depending on where in the stream the corruption lands:
the file's results vanish with no failure and no summary. Running a poisoned file together with a healthy one printed only the healthy file's ok 1 / ok 2 — no 1..N, no # tests, no # fail, no error text. The exit code was 1, but the TAP body reads as a clean pass;
with a length byte below 0x80 but large, the runner waits for a message that never arrives and hangs.
Symptom 2 is the reason I am filing this: on a line that is still in service, a whole test file can drop out of a run while the output looks green, and only the exit code disagrees.
Offer
If the missing step is just a backport-requested-v22.x label or an approval, I am happy to open the [v22.x backport] PR against v22.x-staging — please say so.
Request
Please consider backporting #64706 (fix for #64061) to the
v22.xrelease line.State as of 2026-09-09, checked with the GitHub contents API against
lib/internal/test_runner/runner.js, looking for) >>> 0) + kSerializedSizeHeader:mainv26.xv24.x,v24.x-stagingv22.x,v22.x-staging#64706 carries no
dont-land-on-v22.xlabel, and I could not find an existing backport request or backport PR for v22.x.The line is actively released — the most recent v22 release is v22.23.2 (2026-07-29), three days after #64706 landed on
main(2026-07-26).Why this may deserve more weight than the original report suggested
#64061 was reported as an intermittent CI flake. On v22.19.0 I traced the trigger, and it turns out not to be exotic: it is ordinary non-ASCII text written to stdout by a test.
FileTest.#processRawBufferadvancesbufferHeadpast a consumed message and then reads the next four bytes as a length without re-checking for theFF 0Fheader:When a test's own stdout follows a report message inside the same read, those bytes are interpreted as a length. Every UTF-8 lead/continuation byte is
>= 0x80, so any non-ASCII output — CJK, emoji, accented Latin — can makefullMessageSizenegative, which defeats thebreakguard and hands garbage toDefaultDeserializer.In our repository the emitter was a server start-up banner containing an emoji, printed by the code under test. Three sightings over two days, always the same test file.
Minimal deterministic reproduction
No load, no concurrency, no flakiness. One
write():On v22.19.0, Windows 11 x64:
The only difference between the two runs is whether the trailing stdout is ASCII.
I only have v22.19.0 on this machine, so I have not run this against a fixed release line — the report above is strictly about v22.19.0.
Three symptoms, and one of them is silent
Also observed on v22.19.0, depending on where in the stream the corruption lands:
ok 1/ok 2— no1..N, no# tests, no# fail, no error text. The exit code was1, but the TAP body reads as a clean pass;0x80but large, the runner waits for a message that never arrives and hangs.Symptom 2 is the reason I am filing this: on a line that is still in service, a whole test file can drop out of a run while the output looks green, and only the exit code disagrees.
Offer
If the missing step is just a
backport-requested-v22.xlabel or an approval, I am happy to open the[v22.x backport]PR againstv22.x-staging— please say so.