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.