NU1102: Microsoft.NETCore.App.Runtime.Mono.win-x64 on dotnet publish -r win-x64 — NuGet went looking for a Windows build of Android's Mono runtime, and there is no such package because there is no such thing.

On a multi-target MAUI project, -r win-x64 is applied at restore time to every target framework in the project, not only the one you named with -f. The Android target's runtime is Mono, its runtime packs exist for Android runtime identifiers only, and the restore fails before the Windows build starts. Drop the flag: the Windows target already defaults to win-x64, and the self-contained publish works without it.

The error

From the first Windows publish of the season (abridged — the package and version as the build log recorded them; NuGet's full line also lists every feed it searched):

NU1102: Microsoft.NETCore.App.Runtime.Mono.win-x64 10.0.11 not found

Why it happens

Restore is a project-level step. Even when -f net10.0-windows10.0.19041.0 narrows the build to one target, NuGet still resolves packages for every framework in <TargetFrameworks>, because the assets file it writes covers the whole project. A -r on the command line becomes the RuntimeIdentifier for that whole restore.

Each target then asks for the runtime pack matching its runtime and that identifier. The Windows target wants Microsoft.NETCore.App.Runtime.win-x64, which exists. The Android target runs on Mono, so it wants Microsoft.NETCore.App.Runtime.Mono.win-x64 — a pack that was never published, since Mono on Android ships for android-arm64 and friends. NU1102 is NuGet saying it searched and found nothing. The same command is correct for a single-target app, which is exactly why it looks so natural.

The fix

The publish command that works, from docs/pocket.md in the repo:

dotnet publish src/ClinicLive.Pocket -f net10.0-windows10.0.19041.0 -c Release \
  -p:WindowsPackageType=None -p:WindowsAppSDKSelfContained=true -p:SelfContained=true

No -r. The Windows App SDK targets pick win-x64 for the Windows target on their own, and SelfContained=true still produces the folder you wanted — 643 files, 235 MB, running on a machine with nothing installed. If you genuinely need a different identifier (an ARM64 build, say), set RuntimeIdentifier in the project file inside a condition on the Windows target framework, so the Android restore never sees it. Passing -p:RuntimeIdentifier=win-x64 on the command line has the same problem as -r: it is global.

What the AI got wrong: it reached for the idiomatic self-contained flag from a thousand single-target examples. The lesson of the part was that an exit code is a claim, not a fact; this one at least failed loudly.

Where it bit us

Season three, Part 11: Ship it, on the first attempt at the self-contained Windows publish. Tag pocket-11 in the repo carries the working command and a runbook note saying not to add -r. The lesson: a flag that is right for one project shape is wrong for another, and a multi-target project is a different shape.

Frequently asked

Why does dotnet publish -r win-x64 fail with NU1102 on a .NET MAUI project?
Because the runtime identifier applies to the restore of every target framework in the project, not just the one selected with -f. The Android target uses the Mono runtime, and no Mono runtime pack exists for win-x64, so NuGet reports NU1102 for Microsoft.NETCore.App.Runtime.Mono.win-x64.
How do I publish a self-contained Windows build of a MAUI app?
Run dotnet publish with -f for the Windows target framework, -c Release, and -p:SelfContained=true plus -p:WindowsAppSDKSelfContained=true, and leave out -r. The Windows target defaults to win-x64 on its own, so the runtime identifier flag is unnecessary and breaks the Android restore.
Is -p:RuntimeIdentifier=win-x64 any different from -r win-x64?
No. Both set the RuntimeIdentifier property globally for the restore. To target a specific runtime for one framework only, set RuntimeIdentifier in the project file under a condition that matches the Windows target framework.

More decoded errors in the Fixes category; the whole shipping story is in Part 11.