Repository navigation
MeshWeaver#890 recurred 3x in 30h with the leg-5 reading it was closed waiting for — reopen-or-new-path call needed #5212
Description
MeshWeaver#890 (CI: one Roslyn Emit poisons the whole process; shard ends exit=124) is CLOSED since 2026-09-13. It has now occurred three times inside thirty hours, and each occurrence carries the exact reading that issue said would close a question. The reopen-versus-new-path decision belongs to whoever owns the fix, which is why this is a triage filing and not a reopen.
OCCURRENCES. All three are MeshWeaver.Plugins, workflow Plugin Catalog CI, job portal-hosts (Hosting.Monolith.Test), all exit 124 with no verdict:
- 2026-09-21 13:36Z, run 35606133491, job 106355181093, branch fix/incident-fold-dedupe, platform set 3.0.0-ci.9088 (core 88cd4b7). canary=BELOW-ROSLYN x40, dissect=READS-HEALTHY x40, flat=SAME-FRAME@NamedTypeSymbol.Microsoft.Cci.ITypeDefinitionMember.get_ContainingTypeDefinition x40, compiler=PRIVATE-COPY-EMITS x40.
- 2026-09-21 22:41Z, run 35661949332, job 106544668720, branch fix/hosting-bake-probe, platform set 3.0.0-ci.9108 (core b1aa8a9). Same canary/dissect x58; flat=EMITS for the first SIX failures and flat=SAME-FRAME for the following FIFTY-TWO, in one process; compiler=PRIVATE-COPY-EMITS x58.
- 2026-09-22 11:37Z, run 35722501930, job 106742555061, branch fix/ai-stream-cancel (PR 2231), platform set 3.0.0-ci.9168 (core 620a489). Same canary/dissect x58, flat=EMITS x58, compiler=PRIVATE-COPY-EMITS x58.
WHAT THE READINGS SETTLE. compiler=PRIVATE-COPY-EMITS means a second Roslyn, loaded from fresh bytes into its own collectible context and never executed in this process before, emits the very source the shared copy cannot, in the same process on the same CLR and heap. So BELOW-ROSLYN is void on all three and the dotnet/runtime venue is wrong. And flat= turns out to be a PHASE, not a property of an occurrence: occurrence 2 read both values in one process, shallow first. That closes the 2026-09-08 vs 2026-09-10 contradiction recorded on the issue (one defect at two depths) and retires confined-to-GetConsolidatedTypeParameters-recursion as a general claim. Of the three candidates leg 5 leaves open (the image, its mapping, the native code produced for it), only the third can get worse while a process runs.
NEXT MEASUREMENT, as the issue already prescribes: repeat the private emit until it tiers up. If it then fails, the fault is in what tiering produces; if it never does, it is the shared image or its mapping. This does NOT yet exclude a corrupted static reachable only from the MetadataWriter call site.
WHAT IS NOT THE CAUSE. Not a pull request: three unrelated branches. Not the platform ceiling: three different sets, and the diff between core 6b3fda2 (a set that ran the same suite green, 813 of 813, run 35700505749) and core 620a489 touches nothing under src/MeshWeaver.Compiler or src/MeshWeaver.Compiler.Pipeline, with Microsoft.CodeAnalysis.CSharp 5.9.0 and global.json unchanged.
RATE WITH ITS DENOMINATOR. Since 2026-09-21T00:00Z the unit ran 102 times across the workflow: 75 success, 22 cancelled (superseded pushes), 2 running, 3 failure, and all three failures are this defect. All 102 are pull_request runs: Hosting.Monolith.Test was not selected on main once in that window (main ran Kernel.Test, network-133, Json.Test and others instead), so it passes on main is a zero denominator, not a green, and a single re-run cannot supply the control either.
USER IMPACT. Each occurrence kills an otherwise-healthy pull request run with no verdict, and the red reads as the PR's own until someone spends an hour proving otherwise.
EVIDENCE AND WRITE-UP. Issue comment: github.com//issues/890#issuecomment-5777968513. Committed to Doc/Architecture/NodeTypeCompilation in pull request github.com//pull/5211. Attribution note on the affected PR: github.com/Systemorph/MeshWeaver.Plugins/pull/2231#issuecomment-5777974872.
WHAT I DID NOT ESTABLISH. Whether this is a regression of the fix that closed 890 or a second path to the same symptom; whether a successful emit preceded the first poisoned one in occurrence 3 (successful compiles are not logged, so the evidence is indirect); and the mapping-versus-native-code split, which the tier-up repeat is the experiment for.
Origin: https://memex.systemorph.com/rbuergi/Feedback/890-roslyn-emit-poison-three-occurrences-2026-09-22
filed by the triage agent on behalf of rbuergi via systemorph-com
Activity
rbuergi commentedon Sep 22, 2026
Two amendments to the body above — it was minted from the filing a few minutes before both were established.
1. The rate is a floor, and the floor now states what it could not see. A
cancelledshard cancarry the defect (filtering a population on its conclusion is the exact mistake MeshWeaver#890's
2026-09-12 correction records), so the 22 cancelled executions were read rather than assumed: 18 logs
clean of both
canary=BELOW-ROSLYNandPROCESS CANNOT EMIT, 4 with no retrievable log. 3 of 96determined, 6 undetermined.
2. The "next measurement" as stated could not have been carried out, and this is the part worth
carrying forward. Both #890 and the leg's own printed residual said "repeat the private emit until it
tiers up".
PrivateRoslynCopy.Emitcreates its own collectibleAssemblyLoadContextper invocationand unloads it in
finally(src/MeshWeaver.Compiler/PrivateRoslynCopy.cs:85,:113-115), so N callsare N cold copies — the same tier-0 code measured N times, tiering nothing. The experiment needs
ONE copy held loaded while the emit is repeated inside it, with the unload deferred to the end: a
second entry point, not a loop at the existing one. Caught by the automatic review on
#5211, which corrects it in the XML doc, in the message an
operator actually reads, and in
Doc/Architecture/NodeTypeCompilation.That PR also carries the occurrence table, the
flat=phase finding, and the four dead ends (platformset,
mainas a control, theexit 124arithmetic, the straggler capture). It does not attempt a fix:the reopen-versus-new-path call on #890, and the tier-up entry point, both belong to whoever owns that
issue.
rbuergi commentedon Sep 22, 2026
A fourth occurrence, and a four-day denominator. Widening the sweep to 2026-09-19 found one more,
which also strengthens the attribution: the sets now span four, not three.
flat=compiler=35430730563/1058670582253.0.0-ci.8963(31be311dc)fix/4740-plugins-runner-timeoutsEMITS×52PRIVATE-COPY-EMITS×5235606133491/1063551810933.0.0-ci.9088(88cd4b7b4)fix/incident-fold-dedupeSAME-FRAME@…×4035661949332/1065446687203.0.0-ci.9108(b1aa8a9e5)fix/hosting-bake-probeEMITS×6 thenSAME-FRAME@…×5235722501930/1067425550613.0.0-ci.9168(620a4893a)fix/ai-stream-cancelEMITS×58Denominator. 201 executions of
portal-hosts (Hosting.Monolith.Test)since 2026-09-19T00:00Z: 153success, 39cancelled, 1 running, 8failure— 4 of the 8 are this defect; the other 4 carry nocanary=and noexit 124at all. 🚨 All 201 arepull_requestruns. The unit was not selected onmainonce in four days, so the absence of amaincontrol is a zero denominator over the wider windowtoo, not just the narrow one.
Core's own CI over the same days is a measured negative, and a weak one: 24
MeshWeaver Build and Testruns since 2026-09-20, 13 failed jobs between them, none carryingPROCESS CANNOT EMIT,canary=BELOW-ROSLYNorexit 124. That localises the observation to the Plugins Monolith unit; itdoes not exonerate core, because 13 failures is thin and core's suites do not drive in-process NodeType
compilation at that volume.
And the fault is ACQUIRED, then progressive — both measured. In the newest occurrence
OverlaySelfHealInstanceRecycleTest.OverlaidInstance_SelfRecycles_WhenTypeCompilesGreenpassed at12:52:07.654Z, and that test asserts a NodeType reaching
CompilationStatus.Okwith a usable buildwhose instance then renders a marker — 33 seconds before the first poisoned emit at 12:52:40Z. So
nothing arrived broken. The 22:41Z occurrence supplies the other half inside one process:
flat=EMITSfor six failures, then
flat=SAME-FRAMEfor fifty-two. That is the shape a tier-up produces and notthe shape a bad file produces, which is what makes the (corrected) tier-up experiment worth running.
All of it is in #5211.
rbuergi commentedon Sep 22, 2026
The cleanest control arrived on its own, and it is worth recording as the canonical one for this
failure mode.
Attempt 2 of run
35722501930re-ran the same job (106780475056, 14:07:57Z) with head353b8137bunchanged andplatform mount: set 3.0.0-ci.9168 (core 620a4893a)unchanged, on thesame runner pool, and reported
Test run summary: Passed! total: 813, failed: 0with zerocanary=BELOW-ROSLYN, in 14 minutes against the 900 s cap. Attempt 1 of that same run had 58 canaryblocks and died at
exit 124.One comparison excludes the pull request's diff, the platform set and the content of the suite at
once — none of them changed between the attempts.
🚨 And it names why this defect is expensive to read. A re-run clears it. To whoever re-runs, that
reads as a flake; to whoever only saw attempt 1, it reads as the pull request's fault. It is neither —
it is a process that stopped being able to emit, and the next process that did not. The instrument that
tells the difference is the emit canary in the job log: a control compilation failing alongside the
real ones. Without that line, "some in-mesh compiles NRE'd" reads as bad content in those NodeTypes.
Recorded in #5211.
rbuergi commentedon Sep 24, 2026
Classification: same defect as #890, NOT a new path — and #890 was never closed on a fix, so this is not a regression either. Keep THIS issue as the live tracker; leave #890 closed as the instrument history.
Why, from #890's own record:
completed) when leg 5 of the canary — the pristine-compiler control, feat: leg 5 of the #890 canary — the pristine-COMPILER control (compiler=PRIVATE-COPY-EMITS / THREW) #4165 — was built. Its closing condition, stated on 2026-09-13, was "the reading on an occurrence": an instrument, not a remedy. No change to Roslyn's use, the reference set or the emit path was merged against it after that.PROCESS CANNOT EMIT (#890),canary=BELOW-ROSLYN,dissect=READS-HEALTHY,exit 124onportal-hosts (Hosting.Monolith.Test)), and the leg-5 reading CI: one Roslyn Emit poisons the whole process — every later compile NREs in Cci.MetadataWriter.GetConsolidatedTypeParameters, shard ends exit=124 #890 was waiting for (compiler=PRIVATE-COPY-EMITS) on every one. A "different path sharing the fingerprint" would need a reading that disagrees somewhere; none does.flat=is a phase). Reopening CI: one Roslyn Emit poisons the whole process — every later compile NREs in Cci.MetadataWriter.GetConsolidatedTypeParameters, shard ends exit=124 #890 would bury that under 40 days of superseded readings; this issue carries the current state and fix(#890): the first fourcompiler=readings — and the tier-up instruction they made testable, which was wrong #5211 committed it toDoc/Architecture/NodeTypeCompilation.The next step, precisely (from the 2026-09-22 amendment — the old instruction could not be executed): a second entry point that holds ONE
PrivateRoslynCopyloaded and repeats the emit inside it until it tiers up, deferring the unload to the end (PrivateRoslynCopy.Emittoday creates and unloads a fresh collectible context per call,src/MeshWeaver.Compiler/PrivateRoslynCopy.cs:85,:113-115, so N calls are N cold copies). If the held copy starts failing after tier-up, the fault is in what tiering produces; if it never does, it is the shared image or its mapping. This is diagnosis work on the owner's instrument, not a fix I can make from the evidence here.Not established: the rate since 2026-09-22 14:30Z (I did not re-sweep
portal-hostsruns); whether a corrupted static reachable only from theMetadataWritercall site is excluded (the 2026-09-22 body already says it is not).rbuergi commentedon Sep 24, 2026
It now happens on
main: two occurrences today in a new suite, both starting at the same test, about 6 % of runs of that leg.Widget/Thing08:45:39ZWidget/Thing10:27:55ZBoth are
portal-hosts (network-133 · leg 4/8)runningMeshWeaver.PluginCatalog.Teston runtime 10.0.12 linux-x64 with Roslyn 5.9.0, and both went green on attempt 2. The stack matches every earlier occurrence:CreateIndicesForNonTypeMembers→getConsolidatedTypeParameters×2 →NamedTypeSymbol.ITypeDefinitionMember.get_ContainingTypeDefinition.RetiredNodePruneTest.SharedSourceChange_…compilingWidget/Thing. Earlier emits in the same host had succeeded (ADependentsSource_CompilesAgainstTheTypeItsDependencyShipsassertsOkand passed about 2 minutes before). So the same workload poisons about one process in 16, which means something is decided per process.ConcurrentBuildoff). The defect predates them by a month. Shared references and the sharedCompilationare also out: legs 1 and 2 exclude them, and the private copy emits.AsNestedTypeDefinitionImpl's tier-1 inlines_containingSymbol as NamedTypeSymbolbehind GDV plus a profile-guided cast expansion. Its shape varies per process, which fits per-process randomness, acquire-then-deepen, the cold private copy's immunity, and a consistent frame.DOTNET_JitDisasmlistings of the six methods on that path intotest-logs/jit-890-listing.log. The file is uploaded only when a suite fails. The next occurrence will therefore carry the exact native code that answered the guard. The write-up and how to read the listing are in docs(#5212): #890 on main — one onset position, a per-process harness null, and the JIT-listing capture #5663 (Doc/Architecture/NodeTypeCompilation).Not established: whether production replicas reach this state. A
memexLogsread ofPROCESS CANNOT EMITover 3 h returned 0, with no positive control. The 12 h and 3-day reads on memex and memex-cloud were refused by Loki (timeout, then 429). The harness null is arm64 only. In the 10:27 host, aTypeLoadException … format is invalidonBulkPack/Thing51 s before onset is recorded but not concluded from: that text is also the known load-during-unload tear, and the 08:45 host does not show it.Severity is a triage call I'm leaving open. At
sev:Mthis now reddensmainin about 6 % of runs of this leg.docs(#5212): review — per-attempt reruns, 'not by workload alone', ad…
docs(#5212): full census — 3 of 87 leg executions, all three at the s…
rbuergi commentedon Sep 24, 2026
Census correction to my comment above: the full sweep has now finished. It covers 87 executions of
portal-hosts (network-133 · leg 4/8)from 09-23T00:00Z to 09-24T14:00Z, and 84 of them ran PluginCatalog.Test. 3 carry the canary (≈3.5 %), not 2 of 33. The third is run 35906530904 / job 107342449379 on 09-23 at 19:34Z, set 3.0.0-ci.9263 (core 9a61fed), readingsBELOW-ROSLYN/READS-HEALTHY/flat=SAME-FRAME/PRIVATE-COPY-EMITS×43. Its first poisoned compile is againWidget/ThinginRetiredNodePruneTest.SharedSourceChange_…, so all three occurrences start at the same onset test. #5663 carries the corrected table.docs(#5212): the workflow-wide sweep — six occurrences in 31 h, four …
rbuergi commentedon Sep 24, 2026
Workflow-wide sweep finished. I read every non-success job of every Plugin Catalog CI attempt from 09-23T06:46Z to 09-24T14:00Z (1,060 job logs). It finds six occurrences in 31 h, four of them on main: the three in
network-133 · leg 4/8(PluginCatalog.Test, all starting atWidget/Thing), plus three innetwork-133 · leg 1/8(Hosting.Monolith.Test). Those are 35828369047 (main,TestData/UploadLegWedgeType), 35846873901 and 35858189010 (PRs, both starting atTestData/SatisfiedType). #5663 carries the list.rbuergi commentedon Oct 4, 2026
New attributable occurrence blocking the 9945 fleet arm: Plugins core-candidate run 37211768667, leg 1/12 job 111464402311 (Hosting.Monolith.Test), core
87422043+ Pluginsfd3dbd1e. The host emitted successfully before the first poisoned compile at 2026-10-04 15:15:13 UTC (Systemorph/LinkedInProfile); thenPROCESS CANNOT EMIT (#890)recurred across unrelated NodeTypes. Its first canary has shared/pristineNullReferenceExceptionatNamedTypeSymbol.Microsoft.Cci.ITypeDefinitionMember.get_ContainingTypeDefinition,dissect=READS-HEALTHY,flat=EMITS,compiler=PRIVATE-COPY-EMITS. The leg kept running through many failing assertions, was canceled at 15:53:29, and uploaded a log but no.trx. The paired verdict correctly reportsmissingEvidence: 1, soarm-promoted-setrefused 9945 at 16:15:12; production remains 9939. This is the established acquired process-wide emit failure, not evidence that the 9945 diff caused it. I am investigating the missing JIT capture/root cause; the gate must stay red until there is a valid verdict.rbuergi commentedon Oct 4, 2026
Candidate core-pair run 37211768667 exposed an evidence gap: the ordinary Plugins portal-host lane captures the targeted Roslyn JIT listing, but the core-candidate leg did not, and this canceled host left no .trx. Plugins PR #2873 now adds the same JIT capture to candidate/control leg artifacts and documents it. Local actionlint and workflow-shell parsing pass. The candidate verdict remains red on missing test evidence. This is instrumentation for the next attributable occurrence, not a root-cause fix or a reason to arm 9945; the PR itself is waiting on the required review/CI gate.
6 remaining items
test(#5212): pin NO-BASELINE-MAPPED-DIFFERS; host= and baseline-cost …
Merge pull request #6220 from Systemorph/fix/5212-emit-image-integrit…
rbuergi commentedon Oct 7, 2026
Another occurrence: core PR #6231, head
64317ea803, run job 112723124834 (shard 3,Memex.Portal.Shared.Test).NullReferenceExceptionatNamedTypeSymbol.Microsoft.Cci.ITypeDefinitionMember.get_ContainingTypeDefinitioninMetadataWriter.PopulateNestedClassTableRows. The compile watcher loggedPROCESS CANNOT EMIT (#890)withcanary=BELOW-ROSLYN.InstallNeverInheritsRepoCompileVerdictTestat 09:30:42Z, the 69th of 150 test classes in that process. After it,ModulesUpdateIndependentlyOfThePlatformTest(2 tests) failed with the same NRE.rbuergi commentedon Oct 7, 2026
PR #6231 shard 3 (2 of 2): what a local reproduction attempt established. It did NOT reproduce.
Scope. I set out to reproduce the 2-of-2 onset on PR #6231 locally, bisect the preceding classes, find the mechanism and fix it. None of the 11 local processes reproduced it, so there is no minimal repro and no fix in this comment. Below is what the attempt established and what it excluded. Some of the findings correct earlier statements on this issue.
1. The two CI processes
112723124834and112729207042ran the same tested tree: head64317ea80merged ontomain@fa6bb901bf(fresh merge6930b34bcf38). The tests ranMemex.Portal.Shared.Testpart 1/2 (161 of 321 classes, every second class from the sorted list), with seed1319993060,parallel mode = none, on .NET 10.0.12 linux-x64.VerdictPkg/CataloginInstallNeverInheritsRepoCompileVerdictTest, the 70th class. The 69 classes before it areSettingsRowActionsActOnTheClickedRowTest(Fix chat composer losing focus when prompt ends with question mark #69) and earlier; the full list is reproducible from either log.canary=BELOW-ROSLYN, shared and pristine both THREW atNamedTypeSymbol…get_ContainingTypeDefinition,dissect=READS-HEALTHY,flat=SAME-FRAME,compiler=PRIVATE-COPY-EMITS,held=EMITS(64/64),image=INTACT(metadata, IL of in-scope methods and file hashes all unchanged),host=(.NET 10.0.12 linux-x64 AMD EPYC 7763, 4 cores, avx2, no avx512, tiering=defaults).DiagnosticsNameTheContentTypeAssemblyTest, 09:30:17) and the onset, neither log contains a TypeLoad, BadImageFormat, "format is invalid", unload or AccessViolation line.LinkVerdictPerPlatformTest(2.4 #57, job111891768728),ModulesUpdateIndependentlyOfThePlatformTest(job112147039747), andInstallNeverInherits…(Fix incorrect chat composer behavior when prompt contains slash character #70, today).SettingsRowActions…andPackageUninstallTestcome before the onset in two of the three, but not in the 10-05 job. What all three share is the position: the first compile about 4 to 5 minutes into the process, after a stretch of classes that do not compile.2. 🚨 Correction: CI's seed does not reproduce CI's order locally
xUnit v3 orders test collections by unique IDs that hash the assembly path, so
:<seed>with the same class set runs in a different order on another machine. Measured: same seed, same 161 classes, and locally the first class wasStandInCompileFailureNamesTheEmitCanaryTestwhere CI's wasAFailedPackageNamesItsCauseTest. The 10-06 "full run with CI's seed, 0 failed" therefore did not run CI's order. To replay CI's exact order I used a local-only[assembly: TestCollectionOrderer]plus[assembly: TestMethodOrderer]that read the class and method order from the CI log. The resulting method order diffed empty against CI's.3. Local attempts (all on the merged tree, built Release; 0 of 11 processes poisoned)
DOTNET_PROCESSOR_COUNT=4)TC_CallCountThreshold=5,TC_CallCountingDelayMs=0dotnet msbuild), no canaryEnableWriteXorExecute=0, which qemu needs)Two more harnesses also came back clean:
Microsoft.CodeAnalysis/.CSharpin the process, in the Default ALC, and no collectible ALC is alive at that point.4. What
DOTNET_JitDisasmSummaryshows on x64 (new)MetadataWriter.PopulateNestedClassTableRows,getConsolidatedTypeParameters,FullMetadataWriter.CreateIndicesForNonTypeMembersandNamedTypeSymbol.AsNestedTypeDefinitionImplwere still at (Instrumented) Tier0 through class 71. So locally, class 70 runs unoptimized emit code. Whether CI's process had promoted these methods by then is unknown; nothing in a CI log records it.Tier1 with Synthesized PGO, and none poisons. The Tier1 listing ofAsNestedTypeDefinitionImplon x64 is correct. It does a GDV onSourceNamedTypeSymboland inlines_containingSymbol as NamedTypeSymbolasnull → null,MT == SourceNamedTypeSymbol → self, otherwiseCORINFO_HELP_ISINSTANCEOFCLASS. That is the right null polarity for a top-level type.NotEmitwaits inSettingsRowActions…. That is a fit, not proof.5. Excluded by reading the runtime source (release/10.0)
JIT_ClassProfile32/64recordsDEFAULT_UNKNOWN_HANDLEfor collectible types, and the delegate and vtable probes skip collectible MethodDescs (jithelpers.cpp1957–2189).LoaderAllocatorflushes it (CastCache::FlushCurrentCache(),loaderallocator.cpp:631).PrivateRoslynCopyloads onlyMicrosoft.CodeAnalysisand.CSharpprivately and shares those two from Default, yet it emits. That clears them.flat=SAME-FRAME.PopulateNestedClassTableRowsand the guard path use no pooled objects, and a member-less top-level class can only reach the frame through a guard misread. A corrupted static that is reachable only from the writer's call site is still not formally excluded.6. Incidental finding, found along the way
A stock Linux container (
fs.inotify.max_user_instances=128) fails 305 of 380 tests in this shard withIOException: The configured user limit (128) on the number of inotify instances has been reached. The trace runsServiceSetup.CreateServiceCollection(test/MeshWeaver.Fixture/ServiceSetup.cs:37) →JsonConfigurationSource.Build→PhysicalFilesWatcher. That looks like one config file watcher per test that is never released. GitHub runners evidently allow more instances, so CI does not see it. Not triaged further.7. Next step
This composition reproduced 2 of 2 on CI, so one CI run of shard 3 on this tree is decisive in a way 11 local processes were not. Run it with two arms:
DOTNET_JitStdOutFile+DOTNET_JitDisasmSummary=1+DOTNET_JitDisasm="PopulateNestedClassTableRows AsNestedTypeDefinitionImpl *getConsolidatedTypeParameters* CreateIndicesForNonTypeMembers", which shows whether a Tier1 version of these methods existed before 09:30:42 and what code it contained;DOTNET_TieredPGO=0, the split arm.If (b) is clean and (a) shows a Dynamic-PGO Tier1 body with an inverted null branch, the venue is dotnet/runtime, and that listing is the report. If (a) shows the methods still at Tier0 at onset, the codegen hypothesis is dead and the search moves to process state.
I did not run that experiment: this task excluded CI polling.
rbuergi commentedon Oct 7, 2026
Three more core occurrences on 2026-10-07, all shard 3
Memex.Portal.Shared.Test(part 1/2, 322 class args). They were reported as "caused by #6208 / the fresh-merge base". They are not.cbb3053100(11:15Z), before #6208 mergedcanary=BELOW-ROSLYN×11a9fa0f8dbbfresh-merged onto maincac0664dePROCESS CANNOT EMIT,canary=BELOW-ROSLYN(~4m41s into the process)cac0664decanary=OK(~3m57s in)New in the third one: the shallow phase reads
canary=OK. The first 12 failures are stand-in compiles (StandInCompile.Emit) where the extraMetadataReference.CreateFromImage(...)is invisible (CS0246 'YamlDotNet'×9,CS0246 'PerPlatformVerdictFromTheFuture',CS0234 'MeshWeaver.Test'×2) while the canary, which compiles against the same reference set WITHOUT an extra image reference, still emits. 15 s later (14:53:05Z) the same process readscanary=BELOW-ROSLYN(shared:andpristine:both THREW NRE atMetadataWriter.<GetConsolidatedTypeParameters>). So the canary misses the onset; the "invisible extra reference" symptom comes first in this process.Non-determinism, same inputs: both PR runs tested a fresh merge onto the same main
cac0664dewith nothing in their diffs that reaches the compiler, andLinkVerdictPerPlatformTest/ModuleLinkVersionTestpassed in the #6231 process and failed in the #6244 process. Main's own push run ofcac0664de(37625265553) passed shard 3.Not established: what poisoned either process before the onset (successful compiles are not logged), and I did not attempt a local repro (the 11 null attempts above make it a poor use of time without the JIT/tiering capture from
experiment/5212-jit-capture).rbuergi commentedon Oct 7, 2026
Three more core occurrences on 2026-10-07, all shard 3
Memex.Portal.Shared.Test(part 1/2, 322 class args). They were reported as "caused by #6208 / the fresh-merge base". They are not.cbb3053100(11:15Z), before #6208 mergedcanary=BELOW-ROSLYN×11a9fa0f8dbbfresh-merged onto maincac0664dePROCESS CANNOT EMIT,canary=BELOW-ROSLYN(~4m41s into the process)cac0664decanary=OK(~3m57s in)New in the third one: the shallow phase reads
canary=OK. The first 12 failures are stand-in compiles (StandInCompile.Emit) where the extraMetadataReference.CreateFromImage(...)is invisible (CS0246 'YamlDotNet'×9,CS0246 'PerPlatformVerdictFromTheFuture',CS0234 'MeshWeaver.Test'×2) while the canary, which compiles against the same reference set WITHOUT an extra image reference, still emits. 15 s later (14:53:05Z) the same process readscanary=BELOW-ROSLYN(shared:andpristine:both THREW NRE atMetadataWriter.<GetConsolidatedTypeParameters>). So the canary misses the onset; the "invisible extra reference" symptom comes first in this process.Non-determinism, same inputs: both PR runs tested a fresh merge onto the same main
cac0664dewith nothing in their diffs that reaches the compiler, andLinkVerdictPerPlatformTest/ModuleLinkVersionTestpassed in the #6231 process and failed in the #6244 process. Main's own push run ofcac0664de(37625265553) passed shard 3.Not established: what poisoned either process before the onset (successful compiles are not logged), and I did not attempt a local repro (the 11 null attempts above make it a poor use of time without the JIT/tiering capture from
experiment/5212-jit-capture).rbuergi commentedon Oct 7, 2026
Three more core occurrences on 2026-10-07, all shard 3
Memex.Portal.Shared.Test(part 1/2, 322 class args). They were reported as "caused by #6208 / the fresh-merge base". They are not.cbb3053100(11:15Z), before #6208 mergedcanary=BELOW-ROSLYN×11a9fa0f8dbbfresh-merged onto maincac0664dePROCESS CANNOT EMIT,canary=BELOW-ROSLYN(~4m41s into the process)cac0664decanary=OK(~3m57s in)New in the third one: the shallow phase reads
canary=OK. The first 12 failures are stand-in compiles (StandInCompile.Emit) where the extraMetadataReference.CreateFromImage(...)is invisible (CS0246 'YamlDotNet'×9,CS0246 'PerPlatformVerdictFromTheFuture',CS0234 'MeshWeaver.Test'×2) while the canary, which compiles against the same reference set WITHOUT an extra image reference, still emits. 15 s later (14:53:05Z) the same process readscanary=BELOW-ROSLYN(shared:andpristine:both THREW NRE atMetadataWriter.<GetConsolidatedTypeParameters>). So the canary misses the onset; the "invisible extra reference" symptom comes first in this process.Non-determinism, same inputs: both PR runs tested a fresh merge onto the same main
cac0664dewith nothing in their diffs that reaches the compiler, andLinkVerdictPerPlatformTest/ModuleLinkVersionTestpassed in the #6231 process and failed in the #6244 process. Main's own push run ofcac0664de(37625265553) passed shard 3.Not established: what poisoned either process before the onset (successful compiles are not logged), and I did not attempt a local repro (the 11 null attempts above make it a poor use of time without the JIT/tiering capture from
experiment/5212-jit-capture).rbuergi commentedon Oct 7, 2026
Three more core occurrences on 2026-10-07, all shard 3
Memex.Portal.Shared.Test(part 1/2, 322 class args). They were reported as "caused by #6208 / the fresh-merge base". They are not.cbb3053100(11:15Z), before #6208 mergedcanary=BELOW-ROSLYN×11a9fa0f8dbbfresh-merged onto maincac0664dePROCESS CANNOT EMIT,canary=BELOW-ROSLYN(~4m41s into the process)cac0664decanary=OK(~3m57s in)New in the third one: the shallow phase reads
canary=OK. The first 12 failures are stand-in compiles (StandInCompile.Emit) where the extraMetadataReference.CreateFromImage(...)is invisible (CS0246 'YamlDotNet'×9,CS0246 'PerPlatformVerdictFromTheFuture',CS0234 'MeshWeaver.Test'×2) while the canary, which compiles against the same reference set WITHOUT an extra image reference, still emits. 15 s later (14:53:05Z) the same process readscanary=BELOW-ROSLYN(shared:andpristine:both THREW NRE atMetadataWriter.<GetConsolidatedTypeParameters>). So the canary misses the onset; the "invisible extra reference" symptom comes first in this process.Non-determinism, same inputs: both PR runs tested a fresh merge onto the same main
cac0664dewith nothing in their diffs that reaches the compiler, andLinkVerdictPerPlatformTest/ModuleLinkVersionTestpassed in the #6231 process and failed in the #6244 process. Main's own push run ofcac0664de(37625265553) passed shard 3.Not established: what poisoned either process before the onset (successful compiles are not logged), and I did not attempt a local repro (the 11 null attempts above make it a poor use of time without the JIT/tiering capture from
experiment/5212-jit-capture).rbuergi commentedon Oct 7, 2026
Stopgap (explicit, temporary): while this is open, a core PR whose shard 3 log carries this issue's signature (
canary=BELOW-ROSLYN/PROCESS CANNOT EMIT) is treated as a test-process (harness) death and its failed jobs are re-run ONCE — the poisoned process tells us nothing about the PR. Applied 2026-10-07 to #6244, #6231, #6248 (11 signature lines each). Root cause stays open here: experiment #6245 ran both arms (A: JIT capture, B: TieredPGO=0) clean once — no occurrence, so inconclusive — and is being re-run to catch an occurrence under capture.rbuergi commentedon Oct 7, 2026
Experiment #6245, run 37635375205 attempt 3: the JIT capture caught an occurrence
Arm A (JIT capture, default tiering) failed with this issue's signature in job
112878675728. Arm B (DOTNET_TieredPGO=0, job112878675545) passed. I read the arm A artifactjit-capture-shard3-attempt3(jit.txt, 50 MB) together with the job log and the.trx.Capture coverage
DOTNET_JitStdOutFileappends; it does not overwrite. The one file holds 5 processes run one after another. Each starts with its ownXunitAutoGeneratedEntryPoint:Main, and the summary numbering restarts at1:. TheMemex.Portal.Shared.Testpart-1 process starts at itsMain(file line 902), so the capture covers that process from its very first compile.Timeline (log and trx timestamps; JIT events placed by their position among the test classes' own first-time Tier0 compiles)
ModuleLinkVersionTestruns 11 stand-in emits, all pass. Its last new Roslyn JITs (WithPublicSign,StrongNameKeys) are the last first-time Roslyn compiles before the onsetModuleReloadTransientDownloadTest)MetadataWriter:PopulateNestedClassTableRows() [Tier1 with Synthesized PGO]VerdictPkg/CataloginInstallNeverInheritsRepoCompileVerdictTest, NRE atNamedTypeSymbol…get_ContainingTypeDefinition←PopulateNestedClassTableRows;canary=BELOW-ROSLYN,flat=SAME-FRAME,compiler=PRIVATE-COPY-EMITS,held=EMITS(64/64),image=INTACT,host=(.NET 10.0.12 linux-x64 INTEL XEON PLATINUM 8573C, avx2+avx512f, tiering=defaults)getConsolidatedTypeParametersreaches Tier1. The canary's private-copy legs show up as FullOpts compiles of the same methodsTier of each method at the onset (shared copy, Default ALC)
NamedTypeSymbol:AsNestedTypeDefinitionImplfgCalledCount 190). It is correct, see belowFullMetadataWriter:CreateIndicesForNonTypeMembersMetadataWriter:PopulateNestedClassTableRowsfgCalledCount 205, 17 inlinees with PGO data. Compiled after the last successful emit; the next emit is the onsetgetConsolidatedTypeParametersNo
OSRcompile of any of the four. Each loop method shows twoInstrumented Tier0compiles of identical code size; I have not explained that.The Tier1
PopulateNestedClassTableRowsdropsisinst NamedTypeSymbolRoslyn 5.9.0
SourceMemberContainerTypeSymbol.ContainingTypeisldfld _containingSymbol; isinst NamedTypeSymbol; ret, where the field is aNamespaceOrTypeSymbol. The Tier1 body inlinesAsNestedTypeDefinitionImplbehind a GDV on method-table0x7FB5D6EBAA60and tests the field for null:Neither loop clone has a
CORINFO_HELP_ISINSTANCEOFCLASS. For a top-level source type,_containingSymbolis its namespace, which is non-null. So the guard reads TRUE, the type is written as nested, andContainingTypeDefinitionthrows. That is exactlyflat=SAME-FRAME: a member-less top-level class is enough.Control in the same process, on the same field and the same guessed class. The Tier1
getConsolidatedTypeParameters, compiled just after the onset, carries the same dropped cast in its inlined guard (IG39: mov rdi,[rbx+0x38]; test rdi,rdi; jne IG42). In the same method, another[x+0x38] as NamedTypeSymbolis expanded correctly:IG49: cmp [rax],0x7FB5D6EBAA60; je …/IG50: call CORINFO_HELP_ISINSTANCEOFCLASS. That second site explains the earlier occurrences that failed in thegetConsolidatedTypeParametersframe, and theflat=EMITS→SAME-FRAMEdeepening: one method, then the next, tiers into the same defect. The standalone Tier1AsNestedTypeDefinitionImplguessesSynthesizedReadOnlyListEnumeratorTypeSymbol. For that class the container field is typed as a sealedNamedTypeSymbolsubclass, so leaving the cast out there is legitimate.The leg readings now have an explanation. The private copy lives in a collectible ALC. Collectible code is not tiered: every compile in it is
FullOpts, with no PGO and no GDV. That is whycompiler=PRIVATE-COPY-EMITSandheld=EMITS(64/64)hold every time. It also means the held-copy experiment cannot test tier-up as designed.Verdict
This points to the JIT: Tier1 code with Dynamic PGO that inlines a GDV-guarded callee and loses a class
isinst. It matches the mechanism stated in dotnet/runtime#134193 (anisinstresult inherits the input's non-null-ness), but that issue is about interfaces, so whether it is the same defect is for the runtime team. A report draft is ready, with the listing excerpts, the in-method control and the evidence chain. It has not been filed.Proposed stopgap (not implemented)
Temporary stopgap: set
DOTNET_TieredPGO=0on the test shards. The root cause is the JIT miscompile above. The real fix is the runtime fix, or a runtime version that has it; this setting only avoids the trigger. Production portals compile NodeTypes on the same runtime and the Plugins occurrences show the same signature, so the portals are exposed too. That needs its own decision; this proposal covers test shards only.Is "PGO off prevents it" statistically meaningful? Not yet.
Arm B has 1 clean run against this capture's 1 failure. Arm A failed in 1 of 3 attempts, and recent shard-3 runs fail about 30–50 % of the time. One clean arm proves nothing on its own. I recommend ≥10 paired runs (both arms, same commit and window):
The disassembly already names the mechanism, so the arms are now confirmation, not discovery.
Not established
SourceNamedTypeSymbol._containingSymbolis at +0x38.PEModuleBuilder.SourceModuleis at +0xB0, which matches the listing's[module+0xB0]compare. The release JIT's listing does not print class names.rbuergi commentedon Oct 7, 2026
Filed upstream as dotnet/runtime#135350 (public, maintainer-approved). Searched dotnet/runtime first: no duplicate; dotnet/runtime#134193 (interface
isinstinheriting the input's non-null-ness) is cited there as possibly related, not asserted as the same defect. The public body is the draft from the analysis comment, scrubbed of job ids, repo names and artifact names, with the TieredPGO=0 evidence stated as 1 clean run vs 1 failure against a ~30-50% base rate, and an explicit 'What is NOT established' section (no standalone repro, activation not logged, MT->class mapping inferred).ci(#5212): DOTNET_TieredPGO=0 on the build job too (Roslyn compiler s…
Merge pull request #6268 from Systemorph/fix/5212-tieredpgo-off-env
rbuergi commentedon Oct 11, 2026
Closing: the call this issue asked for is made, the cause is fixed upstream, and no failed test job since the mitigation carries the signature.
The call. Not a reopen of #890's fix and not a second path in our code: a .NET 10 JIT miscompile (Tier1 with dynamic PGO drops a class
isinstin Roslyn's inlinedContainingType), captured in the 2026-10-07 experiment above.Upstream. dotnet/runtime#135350 is closed. The runtime team's fix is dotnet/runtime#135363 ("JIT: Make GenTree::Compare more conservative around several node types"), merged to
mainon 2026-10-08. Their comment says they suspect it fixes this and could not confirm without a repro, so that link is their judgement and not a verified one.Mitigation in this fleet (explicit and temporary — it avoids the trigger, the runtime fix is the cure):
ebdfeb349f(2026-10-07):<TieredPGO>false</TieredPGO>inDirectory.Build.propsandtest/Directory.Build.props, so every host built from this tree runs with Tiered PGO off.e5b965717f(2026-10-07):DOTNET_TieredPGO=0in every emitting CI job and lane, and the chart renders it from the deployment record (the memex record carriesDOTNET_TieredPGO: "0", read from a Restart plan rendered 2026-10-11).Reading (REST, 2026-10-11 ~11:05Z). Failed
MeshWeaver Build and Testruns created since 2026-10-07T18:00Z: 14, among at most 300 failed runs listed for that period (three pages). Their failed test jobs: 20. Job logs carryingPROCESS CANNOT EMITorcanary=BELOW-ROSLYN: 0 of 20. Positive control: the same grep over job112766252743(the 2026-10-07 occurrence on main) finds 11 lines, so the scan can see the signature. Before the mitigation the same shard failed with the signature three times on 2026-10-07 alone.Not established:
TieredPGOsetting waits for one; that is a follow-up, not this issue.Fleet issue wave, Claude Opus 5.5 (agent session).