NETSDK1147: To build this project, the following workloads must be installed: maui-android — the .NET SDK is telling you that a MAUI project needs the MAUI Android workload, and the one your build machine installed was not it.

The cause is one word. dotnet workload install android installs the bare Android workload, which is enough for a plain net10.0-android library but not for a project with <UseMaui>true</UseMaui>. That project needs maui-android, which layers MAUI's targets and packs on top of the Android one. Run dotnet workload install maui-android (or dotnet workload restore from the project folder) and the build proceeds.

The error

From the Android job of the workflow's first run (abridged — the line as the fixing commit recorded it):

NETSDK1147: To build this project, the following workloads must be installed: maui-android

Why it happens

Workloads are layered. android gives the SDK the Android targets, the platform bindings and the tooling to produce an APK. maui-android depends on it and adds the MAUI SDK: the Microsoft.Maui.Sdk targets, the controls packs, the resource pipeline that turns MauiIcon and MauiSplashScreen into Android resources. A project that sets UseMaui asks for that layer, and the SDK checks the installed workload manifests before it compiles anything.

The check is honest to a fault: NETSDK1147 names the exact workload ID it wants. The trap is that the word android appears in both IDs, so a workflow that reads correctly at a glance is wrong by a prefix. And nothing caught it earlier because the development machine had every MAUI workload installed through Visual Studio — the project had never been built on a machine that lacked one. CI was the first.

The fix

The change in .github/workflows/ci.yml, exactly as committed:

      # A MAUI project needs the maui-android workload, not the bare android one.
      # The first real run of this job failed with NETSDK1147 on exactly that.
      - name: Install the MAUI Android workload
        run: dotnet workload install maui-android

      - name: Build the Pocket app (Android, Release)
        run: dotnet build src/ClinicLive.Pocket -f net10.0-android --configuration Release

The alternative is to let the project say what it needs: dotnet workload restore src/ClinicLive.Pocket reads the target frameworks and installs whichever workloads they imply — more robust when targets change, slower on a fresh runner because it may install more than one job needs. The Windows job in the same file installs maui-windows: same prefix, same reason.

What the AI got wrong: it wrote android, which is a real workload with a plausible name, and nothing on the bench could contradict it. A workflow that has never run is a hypothesis, however reasonable it reads.

Where it bit us

Season three, Part 11: Ship it — after publication. The push that published the season was the workflow's first real run: the clinic tests passed, the Windows job passed, and the Android job failed before compiling a line. The fix is the commit on top of tag pocket-11 in the repo, "CI: install maui-android, not android"; the re-run went green on all three targets. The tag keeps the wrong word, because that is what shipped.

Frequently asked

What is the difference between the android and maui-android workloads?
The android workload gives the .NET SDK the Android targets and tooling for any net-android project. The maui-android workload depends on it and adds the .NET MAUI SDK, controls and resource pipeline, which is what a project with UseMaui set to true needs. A MAUI app built with only the android workload fails with NETSDK1147.
How do I fix NETSDK1147 for a .NET MAUI project in GitHub Actions?
Replace dotnet workload install android with dotnet workload install maui-android in the job, or run dotnet workload restore against the project so the SDK installs whatever its target frameworks require. For a Windows target the equivalent workload is maui-windows.
Why did the MAUI build work locally but fail with NETSDK1147 in CI?
Because the development machine already had every MAUI workload installed, usually by Visual Studio, so the project had never been built on a machine without them. CI runners start empty, so the workflow's install step is the first time the requirement is actually tested.

More decoded errors in the Fixes category, or start the season that produced this one at Part 1.