Solved: Fix HTTP Error 500.31 ASP.NET Core Runtime (2026)

You deploy your ASP.NET Core app to IIS. You open the browser. Instead of your app, you get a plain white page with: “HTTP Error 500.31 – Failed to load ASP.NET Core runtime.”

No stack trace. No line number. Just that.

The 500.31 error is specific to the ASP.NET Core Module (ANCM), the IIS module that bridges IIS and the .NET runtime. When ANCM throws 500.31, it means it found your app, started trying to load it, and then couldn’t get the .NET runtime it needs off the ground.

Runtime and server configuration issues are often connected to deeper permission problems. You can also read our Windows permission and ownership error fix guide for additional troubleshooting steps.

The reasons vary more than you’d expect. It could be a missing runtime, a version mismatch, a broken hosting bundle install, a wrong processPath in web.config, or an application pool misconfiguration. This guide walks through each one with the actual fix.

What 500.31 actually means (vs. other 500.3x errors)

IIS has a whole family of ASP.NET Core Module errors in the 500.3x range. Knowing which one you have matters.

  • 500.30: ANCM in-process start failure (the app started loading but crashed during startup)
  • 500.31: ANCM failed to load the runtime entirely (the runtime wasn’t found or couldn’t initialize)
  • 500.32: ANCM failed to load because of a version mismatch
  • 500.33: ANCM request handler load failure
  • 500.34: ANCM mixed hosting models conflict
  • 500.35: ANCM multiple in-process applications in same process

If you see 500.31 specifically, the runtime itself is the problem, not your app code. Your app probably works fine locally. The issue is that IIS on the server can’t locate or load the .NET runtime your app was built for.

Comparison of ASP.NET Core ANCM errors including HTTP Error 500.31

Fix 1: Install the ASP.NET Core Hosting Bundle

This is the right first move. It fixes maybe 70% of 500.31 cases.

The ASP.NET Core Hosting Bundle is what IIS needs to run ASP.NET Core apps. It installs the .NET runtime, the .NET SDK, and the ASP.NET Core Module for IIS in one shot. Without it, IIS has no idea what to do with your app.

Go to dotnet.microsoft.com/download. Find the .NET version your app targets (check your .csproj file for <TargetFramework>). Download the “Hosting Bundle” for Windows, not the SDK and not the runtime alone.

Run the installer on the server. After it finishes, restart IIS completely:

iisreset /stop

iisreset /start

Or open IIS Manager, click the server node in the left panel, and click “Restart” on the right.

Then try loading your app again.

If the hosting bundle was already installed, skip to Fix 2. If you installed it and still get 500.31, the version might be wrong.

If the application still refuses to start after reinstalling the runtime, check our advanced build and execution error troubleshooting guide for related environment and dependency fixes.

Installing ASP.NET Core Hosting Bundle to fix HTTP Error 500.31

Fix 2: Match the runtime version exactly

Your app targets a specific .NET version. IIS needs that exact version installed.

Check what your app needs. Open your project’s .csproj file:

<TargetFramework>net8.0</TargetFramework>

That means your app needs .NET 8. Now check what’s actually installed on the server:

dotnet –list-runtimes

Run that in a Command Prompt on the server. You’ll get output like:

Microsoft.AspNetCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

Microsoft.AspNetCore.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

Microsoft.NETCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

If your app needs .NET 8 and the list only shows .NET 6 and .NET 7, that’s your problem. Install the .NET 8 Hosting Bundle on the server.

Also, check the minor version. An app built with .NET 8.0.5 will fail if only .NET 8.0.1 is installed in some configurations, particularly with self-contained deployments. Install the latest patch version of the hosting bundle for your major version.

Fix 3: Check the application pool settings

IIS application pools have a .NET CLR version setting. For ASP.NET Core apps, this setting should be “No Managed Code.”

Open IIS Manager. Expand the server. Click Application Pools. Find the pool your app is using. Right-click it and choose Basic Settings.

If “.NET CLR version” is set to anything other than “No Managed Code,” change it. ASP.NET Core manages its own runtime. Telling IIS to load a CLR version on top of that causes conflicts.

Also, check the pipeline mode. It should be “Integrated” for most ASP.NET Core apps.

After changing the pool settings, recycle the application pool:

%windir%\system32\inetsrv\appcmd recycle apppool /apppool.name:”YourAppPoolName”

Or right-click the pool in IIS Manager and choose Recycle.

Fix 4: Verify web.config processPath and arguments

Your app’s web.config tells ANCM how to start the application. If this file is wrong, ANCM can’t load the runtime.

Open the web.config in your deployment folder. It should look something like this:

<?xml version=”1.0″ encoding=”utf-8″?>

<configuration>

  <location path=”.” inheritInChildApplications=”false”>

    <system.webServer>

      <handlers>

        <add name=”aspNetCore” path=”*” verb=”*” modules=”AspNetCoreModuleV2″ resourceType=”Unspecified” />

      </handlers>

      <aspNetCore processPath=”dotnet.”

                  arguments=”.\YourApp.dll”

                  stdoutLogEnabled=”false”

                  stdoutLogFile=”.\logs\stdout”

                  hostingModel=”inprocess” />

    </system.webServer>

  </location>

</configuration>

Check these specific things:

processPath: For framework-dependent deployments, this should be dotnet. For self-contained deployments, it should be the name of your exe file, like .\YourApp.exe.

arguments: For framework-dependent deployments, this should point to your DLL: .\YourApp.dll. For self-contained, the arguments attribute can be empty or removed entirely.

modules: Must be AspNetCoreModuleV2. If it says AspNetCoreModule (without V2), your ANCM installation is outdated.

hostingModel: Either in-process or out-of-process. In-process is faster but requires the app pool to run as the same bitness as the runtime. If you’re unsure, try out-of-process first.

A broken web.config is a common result of manual edits or a botched publish. If yours doesn’t match the structure above, regenerate it by publishing fresh from Visual Studio or the CLI:

dotnet publish -c Release -o ./publish

Fix 5: Fix the bitness mismatch (32-bit vs 64-bit)

This one bites people who don’t see it coming.

If your app pool is running in 32-bit mode but your app or the installed runtime is 64-bit (or vice versa), ANCM can’t load the runtime. The 500.31 error appears.

In IIS Manager, click Application Pools. Select your pool. Click Advanced Settings in the right panel. Find “Enable 32-Bit Applications.”

If it’s set to True and your app is a 64-bit app, set it to False. If your app is specifically compiled for x86, set it to True.

For most modern ASP.NET Core apps, “Enable 32-Bit Applications” should be False. 64-bit is the default and what you almost certainly want.

After changing this, recycle the application pool.

Fix 6: Turn on stdout logging to see the real error

The 500.31 browser page is vague on purpose: IIS doesn’t expose detailed error info to browsers by default. But your server has more information if you know where to find it.

Enable stdout logging in web.config:

<aspNetCore processPath=”dotnet.”

            arguments=”.\YourApp.dll”

            stdoutLogEnabled=”true”

            stdoutLogFile=”.\logs\stdout”

            hostingModel=”inprocess” />

Set stdoutLogEnabled to true. Make sure the logs folder exists in your app’s root directory, and that the IIS application pool identity has write access to it.

Reload the page to trigger the error again, then open the log file in the logs folder. The file name starts with “stdout_” followed by a timestamp.

The log will show you the actual exception. Common things you’ll find there:

  • It was not possible to find any compatible framework version → runtime not installed
  • The framework ‘Microsoft.AspNetCore.App’, version ‘8.0.0’ was not found → version mismatch
  • Failed to bind to address → port conflict
  • An actual exception from your app’s startup code → the problem is in your app, not the runtime

Once you’ve diagnosed the issue, set stdoutLogEnabled back to false. Leaving it on in production fills up your disk.

Debugging ASP.NET Core runtime errors using stdout logs in IIS

Fix 7: Repair or reinstall the ASP.NET Core Module

ANCM installs as an IIS module. If that installation is corrupted, partly installed, or conflicting with another version, you’ll get 500.31 even when the runtime itself is fine.

Check whether ANCM is installed at all. Open IIS Manager. Click the server node. Double-click “Modules” in the center panel. Look for “AspNetCoreModuleV2” in the list.

If it’s not there, reinstall the Hosting Bundle. If it is there, the issue might be a corrupted install.

To repair: go to Control Panel, Programs, Programs and Features. Find the “.NET Core Runtime” or “ASP.NET Core Module” entry. Right-click and choose Repair if that option exists, or uninstall and reinstall the Hosting Bundle.

After reinstalling, run iisreset again. This step is easy to skip and easy to forget. The module changes don’t take effect until IIS restarts.

Fix 8: Self-contained deployment issues

If you published your app as self-contained (dotnet publish –self-contained true), the app bundles its own runtime. IIS doesn’t need the hosting bundle in that case, but the web.config needs to match.

For a self-contained deployment, processPath in web.config should point to your exe:

<aspNetCore processPath=”.\YourApp.exe”

            stdoutLogEnabled=”false”

            stdoutLogFile=”.\logs\stdout”

            hostingModel=”outofprocess” />

If your web.config still says processPath=”dotnet” with arguments=”.\YourApp.dll”, IIS will try to use a system-installed dotnet runtime that either doesn’t exist or is the wrong version.

Check your publish profile settings. In Visual Studio, the publish profile (a .pubxml file under Properties\PublishProfiles) controls whether the output is self-contained or framework-dependent. Make sure the profile matches what you intend, and re-publish.

Fix 9: Permissions on the dotnet folder

IIS runs your app under an application pool identity. By default, that’s a virtual account called IIS AppPool\YourAppPoolName. This account needs read and execute permissions on the dotnet installation folder.

If someone locked down C:\Program Files\dotnet with restrictive permissions, the IIS app pool identity can’t load the runtime from there, and 500.31 follows.

Check permissions on C:\Program Files\dotnet. The IIS_IUSRS group (which includes all app pool identities) should have Read and Execute. If it doesn’t, add it:

Open a Command Prompt as Administrator:

icacls “C:\Program Files\dotnet” /grant IIS_IUSRS:RX /t

Then recycle the app pool and try again.

Fix 10: Multiple .NET versions and path conflicts

When multiple .NET versions are installed, the wrong one can get picked up. This is more likely on servers that have been running for years and have accumulated .NET 3.1, 5, 6, 7, and 8 installs.

Check the global.json file in your app’s root if one exists. A global.json that specifies an SDK version can override what dotnet version gets loaded:

{

  “sdk”: {

    “version”: “6.0.100”

  }

}

If the SDK version in global.json doesn’t match what’s installed, dotnet fails to start. Either update global.json to match an installed version, or delete it and let the runtime resolve naturally.

Also, check your PATH environment variable on the server. Run this in Command Prompt:

where dotnet

If it returns multiple paths, the first one wins. Make sure the first path points to the version you need, or that all listed dotnet installations are for the correct version.

Fix 11: Windows Server 2012 and older IIS versions

If you’re deploying to Windows Server 2012 R2 or IIS 8.5, there are additional constraints.

ASP.NET Core Module V2 requires IIS 7.5 or higher and Windows Vista/Server 2008 or higher, but some .NET 8 features require more recent OS versions. If you’re on Server 2012 R2 and targeting .NET 8, check Microsoft’s OS compatibility matrix first.

The hosting bundle installer sometimes silently fails or installs an older ANCM version on older IIS. Check the installed module version in IIS Manager (Modules > AspNetCoreModuleV2 > Properties) and compare it to the version that shipped with your hosting bundle.

Developers using terminal-based fixes may also find our command-line directory navigation tutorial useful when verifying project paths and deployment folders.

For Server 2012 R2, consider using out-of-process hosting. It’s slightly less performant than in-process but has fewer compatibility issues on older IIS versions.

Change hostingModel in web.config:

<aspNetCore processPath=”dotnet.”

            arguments=”.\YourApp.dll”

            stdoutLogEnabled=”false”

            stdoutLogFile=”.\logs\stdout”

            hostingModel=”outofprocess” />

Fix 12: The Event Viewer has more detail than IIS

The Windows Event Viewer often captures ANCM errors with more specificity than what IIS shows in the browser.

Open Event Viewer (search for it in the Start menu). Navigate to Windows Logs, then Application. Look for events from source “IIS AspNetCore Module” or “Application Error.”

The error entries there usually include the sub-error code and a more descriptive message. For example, you might see:

The ASP.NET Core Module was unable to find the native dependencies.

Refer to https://aka.ms/ancm-diagnostics for troubleshooting.

Or a specific exception from the dotnet process that ANCM tried to start.

Sort by date/time and look for errors that match when you loaded the page. This is the fastest way to get from “500.31” to the actual root cause without spending 30 minutes enabling stdout logs.

Deployment checklist before going live

Run through this before every IIS deployment to avoid 500.31 showing up at the worst time:

  1. Confirm the server has the hosting bundle for the exact .NET version your app targets
  2. Confirm the app pool is set to “No Managed Code.”
  3. Confirm “Enable 32-Bit Applications” matches your app’s bitness (almost always False)
  4. Confirm web.config processPath and arguments match your deployment type (framework-dependent vs self-contained)
  5. Confirm AspNetCoreModuleV2 appears in IIS Modules
  6. Confirm the app pool identity has read/execute on C:\Program Files\dotnet
  7. Run iisreset after any hosting bundle install or update
  8. Check Event Viewer after first load to catch anything that didn’t surface in the browser

FAQ

Visual Studio runs your app directly with the dotnet CLI, using whatever runtime is installed on your dev machine. IIS uses ANCM, which has different requirements. The most common cause of this gap: you have .NET installed on your dev machine, but haven’t installed the hosting bundle on the server.

The hosting bundle. The SDK is for development. The server just needs the runtime and ANCM, which the hosting bundle installs. Installing the SDK on a production server works but includes unnecessary tools.

Yes, .NET is designed for side-by-side installations. You can have .NET 6, 7, and 8 all installed at the same time. IIS will use the version your app specifies.

Enable stdout logging, reproduce the error, and read the log. The actual error is almost always in the log. The browser error page is deliberately unhelpful for security reasons.

On Azure App Service, the runtime management is mostly handled for you. You’re more likely to see a different error (like ANCM in-process startup failure) if your app crashes on startup. But 500.31 can appear on Azure if you’ve specified a runtime version in your app settings that isn’t available in the chosen App Service plan tier.

Open IIS Manager. Click the server. Double-click Modules. Find AspNetCoreModuleV2. Right-click it and choose Properties. The DLL path shown there tells you the version. You can also check the file version of the DLL directly in File Explorer.

The error itself isn’t. The browser page shows minimal detail. The risk comes from leaving stdout logging enabled in production, which can expose startup exceptions, including connection strings, if your app logs them. Always disable stdout logging after debugging.

Muhammad Aziz

Muhammad Aziz is a technology writer and digital content creator at BrightColumn, where he simplifies complex topics across AI, software, cybersecurity, and modern tech. He focuses on practical, easy-to-understand guides that help readers solve real-world problems and stay updated with evolving technology.

Leave a Reply

Your email address will not be published. Required fields are marked *