Skip to content

NuGet August 2026 Updates - #3981

Merged
christophwille merged 9 commits into
masterfrom
christophwille/nu0826
Aug 11, 2026
Merged

NuGet August 2026 Updates#3981
christophwille merged 9 commits into
masterfrom
christophwille/nu0826

Conversation

@christophwille

@christophwille christophwille commented Aug 11, 2026

Copy link
Copy Markdown
Member

Includes fix for CI slowdown analysis cislowdown.md

NOTE: to be squash-merged.

@christophwille

Copy link
Copy Markdown
Member Author

Linux CI break analysis (run 31474547911) — 543/1154 ILSpy.Tests failures, Linux only.

All failures share one root cause:

InvalidOperationException
  at SkiaSharp.SkiaSharpVersion.CheckNativeLibraryCompatible(...)
  at SkiaSharp.SkiaApi..cctor()
  ...
  at ICSharpCode.ILSpy.Images..cctor()  (via Avalonia.Svg.Skia.SvgSource.Load)

SkiaSharp's managed assembly refused to load because the native libSkiaSharp.so was too old.

Dependency chain:

  • This PR bumped Svg.Controls.Skia.Avalonia 12.0.0.13 → 12.0.0.14, which bumps Svg.Skia 5.1.1 → 5.2.0.
  • Svg.Skia 5.2.0 moved from SkiaSharp 3.119.x to managed SkiaSharp 4.148.0.
  • The SkiaSharp 4.148.0 meta package only carries the Win32 + macOS native assets transitively. Svg.Skia 5.2.0 lists HarfBuzzSharp.NativeAssets.Linux 14.2.0 explicitly but omits SkiaSharp.NativeAssets.Linux — an upstream packaging gap.
  • The only remaining reference to SkiaSharp.NativeAssets.Linux is from Avalonia.Skia 12.1.1, pinned at 3.119.4.

Result on Linux: managed SkiaSharp 4.148.0 meets native 3.119.4 → the compatibility check throws in SkiaApi..cctor, the Images static ctor dies, and every UI test that touches composition fails. Windows and macOS got matching 4.148.0 natives transitively, which is why only Linux broke.

Resolution: reverted Svg.Controls.Skia.Avalonia to 12.0.0.13 (Svg.Skia 5.1.1), keeping SkiaSharp uniformly at the 3.119.4 that Avalonia aligns with. The other package bumps in this PR are unaffected.

Note for a future retry of this upgrade: taking Svg.Skia 5.2.0+ requires either a matching direct SkiaSharp.NativeAssets.Linux reference (e.g. 4.148.0, verified to exist on NuGet) or waiting for Avalonia to move to SkiaSharp 4.x.

Each test pumped the Avalonia dispatcher through a 900-iteration
trackpad-scroll loop - cheap on a developer machine, but ~200 s per test
on a 4-core hosted runner. Together they made ILSpy.Tests.dll the CI
critical path (~30 min), costing about 7 minutes on the Windows Debug
job and 2-3 minutes on Release. The remaining OpenFromProcessDialog
structure and viewmodel tests keep covering the dialog.

Assisted-by: Claude:claude-fable-5:Claude Code
12.0.0.14 pulls Svg.Skia 5.2.0, which moves to managed SkiaSharp 4.148.0
but ships no matching Linux native assets: the SkiaSharp meta package only
carries the Win32/macOS natives, and Svg.Skia lists the HarfBuzz Linux
natives explicitly while omitting SkiaSharp.NativeAssets.Linux. The only
reference to the Linux natives is Avalonia.Skia's pin at 3.119.4, so on
Linux the managed/native version check throws in SkiaApi..cctor and takes
down every UI test. Staying on the SkiaSharp version Avalonia aligns with
(3.119.4) until Avalonia itself moves to SkiaSharp 4.x.

Assisted-by: Claude:claude-fable-5:Claude Code
The .NET Framework OS module list only contains images the loader maps
via LoadLibrary: NGen native images and mixed-mode assemblies. IL-only
assemblies are memory-mapped without a loader entry - and after a .NET
Framework servicing update the runtime rejects stale native images and
silently falls back to exactly that load path. In that state (any
machine between Patch Tuesday and the ngen update pass) PowerShell's
own assemblies disappear from the module list, so requiring
System.Management.Automation as the test's witness fails even though
the scanner works as designed. Assert GAC provenance of a listed
module instead, which holds regardless of NGen state, and document the
IL-only blind spot on the scanner itself.

Assisted-by: Claude:claude-fable-5:Claude Code
@christophwille

Copy link
Copy Markdown
Member Author

Investigation notes: Only_The_Managed_Modules_Of_A_Desktop_Clr_Process_Are_Listed failure (fixed in bd76559)

Documenting this in detail because the failure mode is environmental and will otherwise look like a flaky test the next time a machine hits the same state.

Symptom

NetFrameworkProcessesTests.Only_The_Managed_Modules_Of_A_Desktop_Clr_Process_Are_Listed failed locally: the module scan of the Windows PowerShell fixture process did not contain System.Management.Automation (neither the IL name nor the .ni.dll native-image name). The other 85 tests in ILSpy.Tests.Windows passed, including the sibling tests asserting mscorlib is listed.

What the module list actually contained

The scan returned only framework assemblies, all of one of two kinds:

  • NGen native images (mscorlib.ni.dll, System.ni.dll, System.Core.ni.dll, System.Xml.ni.dll, ...)
  • The two classic mixed-mode BCL assemblies as IL files (System.Data.dll, System.Transactions.dll)

Conspicuously absent: powershell.exe itself, every Microsoft.PowerShell.* assembly, and System.Management.Automation - i.e. exactly the PowerShell-specific binaries, in a process that was demonstrably executing PowerShell script at the time.

Root cause

Two independent facts combined:

  1. The .NET Framework OS module list only contains images the loader maps via LoadLibrary: NGen native images and mixed-mode assemblies. An IL-only assembly is memory-mapped by the fusion loader without a loader entry, so Process.Modules (PSAPI EnumProcessModules) never sees it. This is why System.Data.dll / System.Transactions.dll (mixed-mode) appear as IL files while every IL-only framework assembly appears only via its .ni.dll.

  2. After a .NET Framework servicing update, the CLR rejects dependent native images as stale until the ngen update task has re-validated/recompiled them, and silently falls back to the invisible IL load. On the machine in question, System.Management.Automation.ni.dll and Microsoft.PowerShell.ConsoleHost.ni.dll exist on disk (regenerated 2026-07-30) and are valid managed PEs, but a freshly started powershell.exe never loads them - verified by polling a live process for minutes: the modules never appear, while the process happily runs script.

So on any machine between a .NET Framework servicing update and the ngen queue catching up (e.g. a CI runner right after Patch Tuesday), PowerShell's own assemblies are legitimately absent from the OS module list. No fix in the scanner can surface them; the test had encoded an environment assumption, not a product invariant.

Side finding, not load-bearing for the failure: on current Windows 11 builds powershell.exe is no longer a managed PE (PEReader.HasMetadata == false), so its absence from the managed-module list is also correct.

Fix

  • Test: the assertion's real intent was "the scan reports assemblies the loader pulled from the GAC, not merely files beside the exe". It now asserts that a listed module comes from under %windir%\assembly (the GAC + NGen store), which holds regardless of NGen validity, with a comment explaining why System.Management.Automation cannot serve as the witness.
  • Scanner doc (NetFrameworkProcesses.Windows.cs): the class comment claimed the desktop loader registers all disk-loaded assemblies in the OS module list. Corrected to state the actual coverage (NGen images + mixed-mode) and to document the IL-only blind spot alongside the already-documented byte-array one. This is a genuine, inherent fidelity gap of the module-list path: for a Framework process running with stale native images, the explorer will list framework assemblies but miss the application's own IL-only ones.

Verification

  • ILSpy.Tests.Windows: 86/86 passing after the fix (was 85/86).
  • ILSpy.Tests (headless Avalonia suite): 1174 passed, 4 skipped, 0 failed - unaffected.

.NET SDK 11.0.100-preview.7 turns the persistent MSBuild server on by
default (dotnet/sdk#55231). With it on, only the first of the three
dotnet pack invocations gets a working SBOM: sbom-tool's Spectre.Console
backend caches the server's RedirectConsoleWriter, which is disposed
when that build session ends, so the later packs in the reused server
process fail their component-detection scan with ObjectDisposedException
(three retries each, surfaced as CI warnings) and ship SBOMs with zero
packages. Disabling the server for the pack step restores the
single-shot MSBuild behavior the scans worked under through preview 6.

Assisted-by: Claude:claude-fable-5:Claude Code
@christophwille

Copy link
Copy Markdown
Member Author

Analysis: new CI warnings on the Windows Release job (run 31524863511)

Compared with the previous master build (run 31458222064), which had only the known WiX InstallerVersion warning, run 31524863511 shows 8 additional warnings, all from the Pack NuGets step:

  • 6x Unknown error while running CD scan: System.ObjectDisposedException: Cannot write to a closed TextWriter.
  • 2x There were no packages detected during the generation workflow.

These are emitted by the SBOM generation that Microsoft.Sbom.Targets runs inside dotnet pack.

Root cause

The workflow installs the SDK as floating 11.0.x / preview. The old run resolved 11.0.100-preview.6.26359.118; the new run got 11.0.100-preview.7.26381.103, released in between. Preview 7 turns the persistent MSBuild server on by default (dotnet/sdk#55231) - Microsoft.Build.Experimental.OutOfProcServerNode appears in the new run's log and never in the old one. No commit on this branch caused it; any fresh master build would now warn the same way.

The failure sequence, visible in the logged stack trace:

  1. The first dotnet pack (ICSharpCode.Decompiler) runs its SBOM component-detection scan successfully; sbom-tool's Spectre.Console backend statically caches the MSBuild server's RedirectConsoleWriter as its output sink.
  2. That build session ends and MSBuild disposes the writer, but the server process lives on.
  3. The next two packs (BamlDecompiler, ILSpyX) reuse the same server process. The scan throws ObjectDisposedException when rendering its detection-summary table through the stale writer, retries 3 times per pack (hence 6 warnings), then generates the SBOM anyway - with zero packages (the 2 remaining warnings).

Impact

Not just log noise: the ICSharpCode.BamlDecompiler and ICSharpCode.ILSpyX nupkgs from that run carry SBOMs with no dependency entries; only the first-packed ICSharpCode.Decompiler got a complete one. The underlying bug is an upstream interaction between microsoft/sbom-tool's console caching and the MSBuild server.

Fix

Commit b772a9f sets DOTNET_CLI_USE_MSBUILD_SERVER: 'false' on the Pack NuGets step - per the preview 7 release notes this is the authoritative opt-out (it forwards MSBUILDUSESERVER=0), restoring the single-shot MSBuild behavior the scans worked under through preview 6.

@christophwille
christophwille merged commit cdeae65 into master Aug 11, 2026
15 checks passed
@christophwille
christophwille deleted the christophwille/nu0826 branch August 11, 2026 19:56
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.

1 participant