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
The browser-wasm ReadyToRun runtime-test leg fails deterministically with a VM GC-mode assert. The failing set is identical across builds, so this is not flaky:
Same 21 work items in both: Directed_do, Directed_r, Directed_ro, JIT.Generics, JIT.opt, Loader, LoaderClassloaderGenerics, Methodical_d1, Methodical_d2, Methodical_do, Methodical_others, Methodical_r1, Methodical_r2, Methodical_ro, Regression_1, Regression_3, Regression_6, Regression_PdbOnly_r_3, Regression_o_3, Regression_ro_2, reflection.
This issue covers the 20 that assert in Object::Validate. The remaining one (reflection) asserts in Thread::ObjectRefFlush and is tracked separately, since Build Analysis matches on text and the two assert texts differ.
Note that Helix categorises these as InfrastructureError. They are not — they are real product asserts in a checked runtime.
#132420 (d1a8a7d2c80, "Route QCall exceptions through marshalling", merged 2026-09-03 20:29 UTC) fixes part of this, but not all of it. Both builds listed above predate that commit; the first post-fix CI run of this leg is build 1582146 (merge commit fcfdc22e638, confirmed to contain d1a8a7d2c80), Helix job f484f658-1090-4625-adf3-8f35293caf50:
This assert still reproduces post-fix.JIT.opt in the post-fix build:
01:19:39.916 Running test: JIT/opt/ThrowHelper/NonVoidThrowHelper/NonVoidThrowHelper.dll
ASSERT FAILED
Expression: !"OBJECTREF being accessed while thread is in preemptive GC mode."
Location: /__w/1/s/src/coreclr/vm/object.cpp:506
Function: Validate
Process: 42
Frame (InterpreterFrame): 0x4fe8b8
So this issue stays open. Note the innermost frame here is InterpreterFrame, whereas the pre-fix JIT.Generics occurrence showed DynamicHelperFrame — the assert is reachable from more than one path, and #132420 addressed only some of them.
Caveat for whoever picks this up: the remaining 17 are not all this shape. Methodical_d1 has no Expression: line in its post-fix log at all, so at least some of the residue is a different failure that still needs triage.
Relationship to existing issues
This is not a new bug. It is the same underlying defect as #131925, and #132022 (closed as a duplicate of #131925) already documented a root cause: a full-framework R2R generic dictionary lookup leaves the thread in preemptive GC mode. The generics-heavy work items are exactly the ones failing, which is consistent — interpreted generic code resolves dictionary lookups inside the VM and never takes the managed QCall path.
A separate issue is filed rather than reusing #131925 because #131925 no longer matches these failures:
Its match block is verbatim text specific to Loader/ContextualReflection/ContextualReflection.dll.
Consequently Build Analysis reports knownIssues: [] for the builds above, and every affected PR sees an unexplained red runtime (Build Monitor Helix Jobs) check.
This issue exists so those PRs can see the failure as known. Consolidate into #131925 if a maintainer prefers.
Error Details
19:52:48.818 Running test: global::JitTest_Generics_Conversions_Reference_GenToGen01.Test_GenToGen01.TestEntryPoint()
ASSERT FAILED
Expression: !"OBJECTREF being accessed while thread is in preemptive GC mode."
Location: /__w/1/s/src/coreclr/vm/object.cpp:506
Function: Validate
Process: 42
Frame (DynamicHelperFrame): 0x4fe8c8
Skipping 0x4fe8c8
Frame (PrestubMethodFrame): 0x4febec
Skipping 0x4febec
Frame (PrestubMethodFrame): 0x4fef2c
Skipping 0x4fef2c
Frame (PrestubMethodFrame): 0x4ff28c
node:internal/process/promises:392
new UnhandledPromiseRejection(reason);
^
UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Debugger not attached".
Node.js v23.11.1
Expected: 100
Actual: 1
END EXECUTION - FAILED
The innermost frame varies by work item — DynamicHelperFrame in JIT.Generics, InterpreterFrame in JIT.opt — so it is deliberately excluded from the match block below.
Error Message
{
"ErrorMessage": [
"Expression: !\"OBJECTREF being accessed while thread is in preemptive GC mode.\"",
"Location: /__w/1/s/src/coreclr/vm/object.cpp:506",
"Function: Validate",
"Process: 42"
],
"ErrorPattern": "",
"BuildRetry": false,
"ExcludeConsoleLog": false
}
Why the match block is scoped this way
This uses the array form: each element matches one line, in order, with arbitrary lines allowed between them.
Two earlier revisions of this issue were wrong, recorded here so the reasoning is auditable:
A regex on the bare assert expression. Too broad — !"OBJECTREF being accessed while thread is in preemptive GC mode." is a single platform-neutral assert site in Object::Validate, and thread->PreemptiveGCDisabled() appears at 26 assert sites across the VM. Either would have matched unrelated failures on any platform and silently marked them known, which is worse than having no KBE.
A single ErrorMessage string with embedded newlines. Build Analysis does not strip newlines and expects one line per signature, so a concatenated block would have matched nothing.
The four elements together scope the match to this failure: the exact assert text, the exact source location, the asserting function, and Process: 42 — emscripten's fixed PID, which native platforms do not report. That last element is what keeps the match on browser-wasm rather than any platform hitting the same assert.
All four elements were verified verbatim against the JIT.Generics console log for Helix job 091c9316-24e7-4e7a-964c-940d0e133fdc. The innermost frame is deliberately excluded because it varies by work item — DynamicHelperFrame in JIT.Generics, InterpreterFrame in JIT.opt.
Match-block verification
Every element was checked verbatim against the failing Helix console log for the job cited above.
The element set (Expression: / Location: / Function: / Process:) mirrors the block in #131925, which matched this same assert 277 times in a month — evidence that these lines are present in the artifact Build Analysis matches against. #131925 stopped matching because its block additionally pins object.cpp:514 (this build reports :506) and text specific to Loader/ContextualReflection, whose test has since been disabled on browser-wasm.
Outstanding: I have not yet observed a Build Analysis run attribute an occurrence to this issue, so the match is reasoned rather than demonstrated. If it does not pick up, the likely cause is that these merged-runner work items abort without publishing a test result for Build Analysis to attach to, in which case the fallback is a test-disable change rather than a KBE.
Build Information
Build: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581582
Build error leg or test failing:
coreclr Pri0 Runtime Tests Run R2R_CG2 browser wasm checked— 20 of 82 Helix work itemsPull request: #133136
The browser-wasm ReadyToRun runtime-test leg fails deterministically with a VM GC-mode assert. The failing set is identical across builds, so this is not flaky:
20b86593-abb9-407d-9cd2-35a9f3ca8784091c9316-24e7-4e7a-964c-940d0e133fdcSame 21 work items in both:
Directed_do,Directed_r,Directed_ro,JIT.Generics,JIT.opt,Loader,LoaderClassloaderGenerics,Methodical_d1,Methodical_d2,Methodical_do,Methodical_others,Methodical_r1,Methodical_r2,Methodical_ro,Regression_1,Regression_3,Regression_6,Regression_PdbOnly_r_3,Regression_o_3,Regression_ro_2,reflection.This issue covers the 20 that assert in
Object::Validate. The remaining one (reflection) asserts inThread::ObjectRefFlushand is tracked separately, since Build Analysis matches on text and the two assert texts differ.Note that Helix categorises these as
InfrastructureError. They are not — they are real product asserts in a checked runtime.Status after #132420
#132420 (
d1a8a7d2c80, "Route QCall exceptions through marshalling", merged 2026-09-03 20:29 UTC) fixes part of this, but not all of it. Both builds listed above predate that commit; the first post-fix CI run of this leg is build 1582146 (merge commitfcfdc22e638, confirmed to containd1a8a7d2c80), Helix jobf484f658-1090-4625-adf3-8f35293caf50:Fixed by #132420:
Directed_r,JIT.Generics,LoaderClassloaderGenerics,reflection.Still failing:
Directed_do,Directed_ro,JIT.opt,Loader,Methodical_d1,Methodical_d2,Methodical_do,Methodical_others,Methodical_r1,Methodical_r2,Methodical_ro,Regression_1,Regression_3,Regression_6,Regression_PdbOnly_r_3,Regression_o_3,Regression_ro_2.This assert still reproduces post-fix.
JIT.optin the post-fix build:So this issue stays open. Note the innermost frame here is
InterpreterFrame, whereas the pre-fixJIT.Genericsoccurrence showedDynamicHelperFrame— the assert is reachable from more than one path, and #132420 addressed only some of them.Caveat for whoever picks this up: the remaining 17 are not all this shape.
Methodical_d1has noExpression:line in its post-fix log at all, so at least some of the residue is a different failure that still needs triage.Relationship to existing issues
This is not a new bug. It is the same underlying defect as #131925, and #132022 (closed as a duplicate of #131925) already documented a root cause: a full-framework R2R generic dictionary lookup leaves the thread in preemptive GC mode. The generics-heavy work items are exactly the ones failing, which is consistent — interpreted generic code resolves dictionary lookups inside the VM and never takes the managed QCall path.
A separate issue is filed rather than reusing #131925 because #131925 no longer matches these failures:
Loader/ContextualReflection/ContextualReflection.dll.24-Hour: 0 | 7-Day: 0hits and is effectively dormant.knownIssues: []for the builds above, and every affected PR sees an unexplained redruntime (Build Monitor Helix Jobs)check.This issue exists so those PRs can see the failure as known. Consolidate into #131925 if a maintainer prefers.
Error Details
The innermost frame varies by work item —
DynamicHelperFrameinJIT.Generics,InterpreterFrameinJIT.opt— so it is deliberately excluded from the match block below.Error Message
{ "ErrorMessage": [ "Expression: !\"OBJECTREF being accessed while thread is in preemptive GC mode.\"", "Location: /__w/1/s/src/coreclr/vm/object.cpp:506", "Function: Validate", "Process: 42" ], "ErrorPattern": "", "BuildRetry": false, "ExcludeConsoleLog": false }Why the match block is scoped this way
This uses the array form: each element matches one line, in order, with arbitrary lines allowed between them.
Two earlier revisions of this issue were wrong, recorded here so the reasoning is auditable:
!"OBJECTREF being accessed while thread is in preemptive GC mode."is a single platform-neutral assert site inObject::Validate, andthread->PreemptiveGCDisabled()appears at 26 assert sites across the VM. Either would have matched unrelated failures on any platform and silently marked them known, which is worse than having no KBE.ErrorMessagestring with embedded newlines. Build Analysis does not strip newlines and expects one line per signature, so a concatenated block would have matched nothing.The four elements together scope the match to this failure: the exact assert text, the exact source location, the asserting function, and
Process: 42— emscripten's fixed PID, which native platforms do not report. That last element is what keeps the match on browser-wasm rather than any platform hitting the same assert.All four elements were verified verbatim against the
JIT.Genericsconsole log for Helix job091c9316-24e7-4e7a-964c-940d0e133fdc. The innermost frame is deliberately excluded because it varies by work item —DynamicHelperFrameinJIT.Generics,InterpreterFrameinJIT.opt.Match-block verification
Every element was checked verbatim against the failing Helix console log for the job cited above.
The element set (
Expression:/Location:/Function:/Process:) mirrors the block in #131925, which matched this same assert 277 times in a month — evidence that these lines are present in the artifact Build Analysis matches against. #131925 stopped matching because its block additionally pinsobject.cpp:514(this build reports:506) and text specific toLoader/ContextualReflection, whose test has since been disabled on browser-wasm.Outstanding: I have not yet observed a Build Analysis run attribute an occurrence to this issue, so the match is reasoned rather than demonstrated. If it does not pick up, the likely cause is that these merged-runner work items abort without publishing a test result for Build Analysis to attach to, in which case the fallback is a test-disable change rather than a KBE.
Note
This issue was authored with GitHub Copilot.
Report
Summary