Fix .NET MAUI Setup & Build Errors (2026 Guide)

Microsoft Fix Intermediate 14 min read Official Docs Grounded Updated April 20, 2026

Why .NET MAUI Breaks , And Why the Error Messages Don't Help

You've seen it. You fire up Visual Studio, create a brand-new .NET MAUI project targeting Android, iOS, macOS, and Windows from a single shared codebase , exactly what the framework promises, and then the build explodes with something like NETSDK1045, a missing workload, or a cryptic Xcode license error. You didn't touch anything. You followed the quickstart. And yet here you are.

I've seen this exact situation on dozens of developer machines, and the root causes almost always fall into a few predictable categories. Understanding which one you're hitting is the fastest path out.

Workload mismatch. .NET MAUI installs as a set of SDK workloads on top of the .NET runtime. If your .NET SDK version and your installed MAUI workload version are out of sync, say you updated the SDK via Windows Update or a standalone installer but didn't re-run dotnet workload restore, you'll get errors that look unrelated to what actually happened. Visual Studio's "Repair" button often doesn't fix this because it operates on the VS component, not the underlying SDK workloads.

Android SDK configuration drift. The .NET MAUI Android target requires specific Android SDK components, platform versions, and build tools. If you've upgraded Android Studio separately, changed the ANDROID_HOME environment variable, or installed multiple SDK instances, .NET MAUI's MSBuild integration loses track of what to use. The error messages it produces, things like "Unable to find android.jar" or a silent failure on dotnet build -t:Run -f net10.0-android, are genuinely misleading.

Single-project structure confusion. One of .NET MAUI's core design decisions is a single-project architecture where one .csproj targets multiple platforms through multi-targeting. That's elegant in theory but means your project file carries platform-specific MSBuild conditions, and when something's wrong with one target framework moniker (TFM), the error surfaces in ways that look like the whole project is broken. It's often just one TFM.

Xamarin migration residue. A huge proportion of the developers I talk to are migrating from Xamarin.Forms. The .NET Upgrade Assistant can handle a lot of the heavy lifting, but it leaves behind deprecated API calls, old NuGet package references, and XAML namespace prefixes that don't exist in .NET MAUI. Those don't always fail loudly, sometimes they just silently break data binding or cause app lifecycle events to fire in the wrong order.

Hot Reload and XAML Compilation fighting each other. .NET MAUI XAML is compiled at build time by default (XamlCompilation is opt-in per class but enabled globally in modern templates). When Hot Reload is active and you're also running XAML compilation, a stale compiled XAML type can conflict with the live-reloaded version, producing XamlParseException at runtime with a stack trace pointing at line 1 of every file.

I know how frustrating this is, especially when your deadline is tomorrow and you're stuck on tooling rather than writing actual app code. The good news is that every one of these is fixable. Browse all Microsoft fix guides →

The Quick Fix, Try This First

Before you spend an hour in the Android SDK Manager or start editing project files, run this sequence. It resolves the majority of .NET MAUI build failures caused by workload drift and corrupted local caches.

Open a terminal, either the Developer Command Prompt in Visual Studio or plain Windows Terminal, and run these three commands in order:

dotnet workload repair
dotnet workload update
dotnet nuget locals all --clear

Here's what each one actually does. dotnet workload repair re-installs the currently pinned workload versions from scratch, overwriting anything that got partially installed or corrupted. dotnet workload update pulls the latest compatible workload manifests for your SDK band. dotnet nuget locals all --clear wipes every local NuGet cache, the http-cache, the global packages folder, the temp folder, all of it. A corrupt or version-mismatched cached package is the silent killer of MAUI build pipelines.

After all three complete, close Visual Studio completely. Don't just close the project, close the IDE. Then reopen your solution and do a full rebuild with Build > Rebuild Solution. If you're on a Mac targeting iOS, also run sudo xcode-select --reset in Terminal before reopening Rider or VS for Mac.

This sequence fixes roughly 60–70% of the ".NET MAUI suddenly stopped building" cases I've handled. If you're still seeing errors after this, move to the step-by-step section, the remaining cases need more targeted surgery.

Pro Tip
Run dotnet workload list before and after the repair. You should see maui, maui-android, maui-ios, and maui-windows all listed with matching version numbers. If any of them show a different version from the others, that mismatch is almost certainly your root cause, and workload repair will normalize them all in one shot.
1
Verify and Repair the .NET MAUI Workload Installation

The very first thing to confirm is that your installed workload actually matches your SDK version. This sounds obvious but it trips up experienced developers constantly, especially on machines where multiple .NET SDK versions coexist.

Run this to see exactly what's installed:

dotnet --list-sdks
dotnet workload list

You're looking for alignment. If dotnet --list-sdks shows 10.0.100 as your active SDK but dotnet workload list shows MAUI at a version built for 8.0.x, that's your problem. The workload manifests are SDK-band-specific, a workload built for the 8.0 band won't work correctly under the 10.0 band.

To fix it explicitly:

dotnet workload install maui --sdk-version 10.0.100

On Windows, if you installed .NET MAUI through the Visual Studio Installer, you should also check there. Open Visual Studio Installer > Modify > Mobile development with .NET and make sure the workload is checked. Then scroll down in the right pane and verify that .NET MAUI, Android SDK setup, and Google Android Emulator are all selected. Hit Modify and let it complete fully before trying to build again.

When it's working, dotnet build -f net10.0-android should produce output ending with Build succeeded and zero errors. If you still see NETSDK1045 (current .NET SDK does not support targeting), your global.json might be pinning an older SDK version, check for a global.json file in your solution root and update or remove it.

2
Configure the Android SDK Path and Build Tools

Android targeting in .NET MAUI depends on MSBuild being able to find three things: the Android SDK root, the correct platform version (the android.jar for your target API level), and a compatible set of build tools. When any of these is missing or pointing at the wrong location, the build fails with errors that look completely unrelated.

First, find where your Android SDK actually lives. On Windows it's usually one of:

C:\Users\{username}\AppData\Local\Android\Sdk
C:\Program Files (x86)\Android\android-sdk

Check your ANDROID_HOME environment variable:

# In PowerShell
$env:ANDROID_HOME

If it's blank or pointing at a directory that doesn't exist, set it:

[System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "C:\Users\{username}\AppData\Local\Android\Sdk", "User")

Next, open the Android SDK Manager inside Visual Studio: Tools > Android > Android SDK Manager. Under the Platforms tab, make sure you have at least Android API 21 (the minimum .NET MAUI requires) and your target API level installed. Under Tools, confirm you have Android SDK Build-Tools 34.0.0 or higher installed. Missing build tools are a very common cause of the "Build tools revision 30.0.3 is too low" error.

After making SDK changes, restart Visual Studio completely. The MSBuild integration caches SDK discovery results at startup and won't pick up changes until the IDE restarts. When configured correctly, you should see your Android emulators listed under the debug target dropdown in the toolbar.

3
Resolve XAML Compilation and Hot Reload Conflicts

.NET MAUI's XAML hot reload feature is genuinely useful, you can see UI changes reflected in a running app without a full recompile. But it has a known tension with compiled XAML. When you're getting XamlParseException at runtime, or your UI changes aren't appearing during hot reload sessions, here's the diagnostic approach that works.

First, confirm XAML compilation is enabled at the class level where you expect it. In .NET MAUI, XAML compilation is on by default for the whole assembly via the generated AppDelegate/MainActivity, but individual pages that were migrated from Xamarin sometimes carry the old opt-in attribute:

[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class OldPage : ContentPage { }

That Skip value is the culprit when you see runtime parse errors that should have been caught at build time. Change it to XamlCompilationOptions.Compile or remove the attribute entirely to inherit the assembly default.

For hot reload specifically: if XAML Hot Reload isn't reflecting your changes, check Tools > Options > XAML Hot Reload and make sure Enable XAML Hot Reload is checked. Also verify you're running a Debug build, not Release, hot reload is disabled in Release configurations entirely. If it's enabled but still not working, do a clean build (Build > Clean Solution, then Build > Rebuild Solution) to flush any stale compiled XAML artifacts from the obj/ directory. The obj folder is where compiled XAML intermediate files live, and they can get into an inconsistent state after rapid edits.

A clean rebuild should result in hot reload working again within your next debug session. You'll see the MAUI Hot Reload output pane show "Hot Reload applied" when changes are picked up successfully.

4
Fix App Lifecycle and Startup Crash Issues

Some of the most confusing .NET MAUI issues aren't build errors at all, the app builds fine but crashes on launch, or it works on Android and dies immediately on iOS. These are almost always app lifecycle problems. The .NET MAUI app lifecycle is well-documented but has important differences from what Xamarin developers are used to.

The startup sequence in .NET MAUI goes through MauiProgram.CreateMauiApp(), that's where your dependency injection registrations, fonts, handlers, and services all wire up. If something throws during this phase, the app crashes before any UI is shown, and the exception can be swallowed silently on device depending on the platform's crash reporting behavior.

To diagnose startup crashes, always run attached to the debugger first. In Visual Studio, set your startup project to the MAUI project (not a platform-specific one), hit F5, and watch the Output window, specifically the Debug output channel, not the Build channel. Unhandled exceptions during CreateMauiApp() will appear there even if the app silently exits.

Common startup crash causes I see repeatedly:

// Missing font file, will throw FileNotFoundException at startup
builder.ConfigureFonts(fonts =>
{
    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); // file must exist in /Resources/Fonts/
});

Check that every font file referenced in MauiProgram.cs actually exists under Resources/Fonts/ and has its Build Action set to MauiFont in the Properties pane. Same rule applies to images (MauiImage) and splash screens (MauiSplashScreen). Wrong build actions are a silent killer, the file is there but the framework can't find it.

For lifecycle-specific events like OnStart, OnSleep, and OnResume, these now live in the App class via overrides, not in platform-specific files. If you migrated from Xamarin and your background/foreground logic isn't working, check the official app lifecycle documentation and verify your overrides are on the correct class.

5
Resolve Platform Deployment and Publishing Errors

Getting the app to run in the emulator is one thing. Getting it deployed to a real device or published to an app store is where .NET MAUI's multi-platform nature creates genuine complexity. Here are the most common deployment failures and exactly how to fix them.

Android, Device not recognized: If your physical Android device doesn't appear in the deployment target dropdown, check USB debugging first. On the device: Settings > About Phone > tap Build Number 7 times > Developer Options > USB Debugging: ON. Then run:

adb devices

If the device shows as unauthorized, unplug and replug the USB cable and accept the RSA fingerprint dialog on the device. If it shows as offline, run adb kill-server followed by adb start-server.

Windows, Unpackaged vs. packaged deployment: .NET MAUI Windows apps can be deployed as MSIX-packaged or unpackaged. Packaged deployment requires a code signing certificate. If you're seeing DEP0700: Registration of the app failed, you either have a certificate mismatch or Windows developer mode isn't enabled. Enable it at Settings > Privacy & Security > For Developers > Developer Mode: On.

iOS, Provisioning profile errors: iOS deployment requires a valid provisioning profile linked to your Apple Developer account. In Visual Studio, open Tools > Options > Xamarin > Apple Accounts (yes, still Xamarin in some VS versions) and verify your account is listed. Then in your project properties under iOS Bundle Signing, set both the signing identity and provisioning profile to Automatic to let Visual Studio resolve them. Manual profile selection with a stale profile is the most common cause of IPA signing failures.

For all platforms, the official .NET MAUI deployment documentation covers the wireless deployment workflow as well, which lets you deploy to iOS devices over Wi-Fi without a USB cable once the initial pairing is done.

Advanced Troubleshooting, When the Standard Fixes Don't Work

If you've been through the five steps above and you're still hitting walls, these advanced techniques are where the real answers live. These apply especially to enterprise environments, CI/CD pipelines, and machines managed by Group Policy or MDM.

MSBuild binary log analysis. The single most useful debugging tool for stubborn .NET MAUI build failures is the MSBuild binary log. Run your build with:

dotnet build -f net10.0-android -bl:build.binlog

Then open build.binlog with the MSBuild Structured Log Viewer (free download from the MSBuild GitHub). This shows you the complete build graph, every target that ran, every property value, every imported SDK file. What looks like a cryptic one-line error in the terminal is almost always traceable to a specific MSBuild target that failed fifteen levels deep. I've diagnosed workload version mismatches, missing Android SDK components, and broken NuGet restore in under three minutes with this tool.

Multi-targeting isolation. In a .NET MAUI single project, you can temporarily disable platform TFMs to isolate which one is causing the problem. Open your .csproj and find the <TargetFrameworks> element. Comment out all but one TFM:

<TargetFrameworks>net10.0-android<!--;net10.0-ios;net10.0-maccatalyst;net10.0-windows10.0.19041.0--></TargetFrameworks>

Build against just Android. Then just iOS. This narrows down whether you have a framework-agnostic error (build fails on all TFMs) or a platform-specific one. Framework-agnostic errors are usually NuGet package incompatibilities or C# code that uses APIs not available in a particular TFM. Platform-specific errors point at SDK configuration.

Native AOT and trimming issues. If you're publishing with <PublishTrimmed>true</PublishTrimmed> or Native AOT enabled (which .NET MAUI supports as of .NET 9+), you may see runtime crashes that don't reproduce in Debug builds. These are trimming errors, the linker removed a type or method that's accessed via reflection. The fix is adding trimming annotations or a TrimmerRootDescriptor XML file. Check the official .NET MAUI trimming documentation for the descriptor format.

CI/CD and headless build environments. Building .NET MAUI in a CI pipeline (Azure DevOps, GitHub Actions) requires the workloads to be explicitly installed in the pipeline definition. The Visual Studio Installer doesn't run in CI. Add this to your pipeline YAML before the build step:

- script: dotnet workload install maui
  displayName: 'Install .NET MAUI workload'

Also pin your .NET SDK version using a global.json in the repo root, CI agents frequently have multiple SDK versions and will pick the wrong one without explicit pinning.

Xamarin migration residue, deep check. After running the .NET Upgrade Assistant, search your entire solution for these patterns that the assistant sometimes misses: Xamarin.Forms namespace references in XAML files, Device.RuntimePlatform (replaced by DeviceInfo.Platform), DependencyService.Get<T>() (replaced by .NET DI), and MessagingCenter (replaced by WeakReferenceMessenger from the .NET Community Toolkit). Any of these left in place will cause build warnings that turn into runtime failures.

When to Call Microsoft Support

If you've confirmed your workloads are correctly installed, your Android SDK is properly configured, your project builds cleanly from the command line but not in Visual Studio, and you've checked the MSBuild binary log and can't identify the failing target, that's a tooling bug, not a configuration issue. Open a ticket with Microsoft Support and include the binary log file. Also consider filing an issue on the dotnet/maui GitHub repository, which the .NET MAUI team actively monitors. Include your dotnet --info output, dotnet workload list output, and the binary log, that's exactly what they'll ask for.

Prevention & Best Practices, Keep .NET MAUI Builds Healthy

The developers who never seem to hit these problems aren't lucky, they've just built a set of habits that prevent the most common failure modes. Here's what I tell every team that's adopting .NET MAUI seriously.

Pin your SDK version. Add a global.json to your solution root the moment you start a new project. Specify the exact SDK version your project requires. This prevents the silent SDK upgrade problem where a developer's machine or CI agent gets a new SDK band that the installed workloads don't yet support.

{
  "sdk": {
    "version": "10.0.100",
    "rollForward": "latestPatch"
  }
}

latestPatch allows patch updates (security fixes) while blocking minor and major upgrades until you explicitly update the file. That's the right balance between security and stability.

Run workload updates as part of your sprint cadence. Don't let workloads drift for months. Once every two weeks, run dotnet workload update. Do it when you're not under deadline pressure. That way you catch breaking changes early when you have time to deal with them, rather than the night before a release.

Use the single-project structure as designed. Resist the temptation to add platform-specific projects back as separate .csproj files unless you have a very specific reason. The .NET MAUI single project with multi-targeting and the Platforms/ folder for platform-specific code handles the vast majority of use cases. Fighting the architecture costs more than it saves.

Test on real devices early. Emulators are great for iteration but they don't catch all platform-specific issues, especially around permissions, app lifecycle events when the OS terminates your app for memory, and platform-specific layout rendering. Add real device testing to your process from the first sprint, not the last.

Keep your XAML and C# in sync. MAUI's code-behind partial class pattern means your XAML and your C# file share a class. If you rename a control in XAML and forget to update the code-behind reference, you'll get a build error. It's obvious when it happens, but consistently using the IDE's rename refactoring (F2 in Visual Studio) instead of manual text edits prevents this class of error entirely.

Quick Wins
  • Add global.json to every MAUI solution and pin the SDK version from day one
  • Run dotnet workload repair && dotnet workload update before any major SDK upgrade
  • Clear the NuGet global packages cache (dotnet nuget locals all --clear) whenever builds become inconsistently flaky
  • Enable the MSBuild binary log in your CI pipeline so you have a complete build trace for every failed run, storage is cheap, debugging blind is not

Frequently Asked Questions

What is .NET MAUI and how is it different from Xamarin.Forms?

.NET Multi-platform App UI (.NET MAUI) is the official successor to Xamarin.Forms, built directly into the .NET ecosystem rather than as a separate product. The key differences are architecture-deep: .NET MAUI uses a single-project structure where one .csproj targets Android, iOS, macOS, and Windows simultaneously through multi-targeting, while Xamarin.Forms required separate head projects per platform. .NET MAUI also has a new handler-based rendering architecture that replaces Xamarin's renderer pattern, offering better performance and easier customization. If you're on Xamarin, Microsoft's .NET Upgrade Assistant can migrate most of your project automatically, though you'll need to manually update deprecated APIs like Device.RuntimePlatform and DependencyService.

Which platforms does .NET MAUI support in 2026?

As documented by Microsoft, .NET MAUI supports Android, iOS, macOS (via Mac Catalyst), and Windows from a single shared codebase. The supported platform versions change with each .NET release, so always check the official "Supported platforms" page for the exact minimum OS versions required by the .NET MAUI version you're targeting, for example, Windows support requires Windows 10 version 1809 or higher. There is also first-class support for .NET MAUI Blazor Hybrid apps, which let you embed Blazor web UI components inside a native MAUI shell, giving you a path to share code between web and native app targets as well.

Why does my .NET MAUI app build fine on my machine but fail on CI?

This is almost always a workload installation problem. Your local machine has .NET MAUI workloads installed via Visual Studio, but CI agents start clean and only have whatever the base .NET SDK image provides. Add an explicit dotnet workload install maui step to your pipeline definition before any build or test steps. Also check that your global.json pins the same SDK version that's available on your CI agent, a mismatch here causes the workload install to install for the wrong SDK band, which then fails silently. Check the agent's available SDK versions with a dotnet --list-sdks diagnostic step if you're unsure.

How do I fix "Unable to find android.jar for API level XX" in .NET MAUI?

This error means the Android SDK platform package for the target API level isn't installed. Open Visual Studio and navigate to Tools > Android > Android SDK Manager. Under the Platforms tab, find the API level mentioned in the error and install it. While you're there, also confirm that your ANDROID_HOME environment variable points to the correct SDK root, if you have multiple Android SDK installations from Android Studio and Visual Studio, .NET MAUI's MSBuild tasks can pick the wrong one. Set ANDROID_HOME explicitly in your system environment variables to point at the SDK that has all the required components installed, then restart Visual Studio.

How do I migrate from Xamarin to .NET MAUI, what does the Upgrade Assistant actually do?

The .NET Upgrade Assistant (available as a Visual Studio extension or a global dotnet tool) handles the mechanical parts of migration: it converts your .csproj files to SDK-style format, updates NuGet package references from Xamarin.Forms to .NET MAUI equivalents, updates XAML namespace prefixes, and restructures your project to use the single-project layout. What it doesn't handle is any API that was deprecated between Xamarin.Forms and .NET MAUI, you'll need to manually replace DependencyService with .NET DI, MessagingCenter with WeakReferenceMessenger, and Device.RuntimePlatform with DeviceInfo.Platform. The official Microsoft migration guides cover each deprecated API with its replacement, and I'd recommend going through that list methodically after the assistant finishes.

XAML Hot Reload stopped working in .NET MAUI, how do I get it back?

The first check is always whether you're running a Debug build, XAML Hot Reload is explicitly disabled in Release configurations and there's no way to override that. Assuming you're in Debug, go to Tools > Options > XAML Hot Reload and verify the feature is enabled. If it's enabled but changes aren't appearing, the most reliable fix is a full clean rebuild: Build > Clean Solution then Build > Rebuild Solution. This clears the compiled XAML intermediate files in your obj/ directories that can get into a stale state. If it still doesn't work after a clean rebuild, check that your App.xaml and the page you're editing don't have [XamlCompilation(XamlCompilationOptions.Skip)] applied, that attribute disables compiled XAML and can interfere with hot reload's patching mechanism in some versions.

Related Microsoft Fix Guides

H
Sai Kiran Pandrala
Our team includes certified Microsoft engineers, Azure architects, and system administrators with 10+ years of enterprise IT experience. Every guide is written from hands-on troubleshooting, not guesswork. We test every fix before publishing.