ASP.NET Core HTTP Error 500.30: Causes and Production Fixes
The HTTP Error 500.30 — ASP.NET Core app failed to start message is one of the most common — and one of the least informative — error pages a .NET developer can see in production. The IIS-level page tells you the app crashed during startup, but rarely tells you why. This guide walks through the eight failure modes that account for almost every real-world 500.30 we see on Windows hosting, in the order you should check them.
What HTTP 500.30 actually means
500.30 is emitted by the ASP.NET Core Module (ANCM) — the IIS module that forwards requests into the Kestrel-hosted .NET runtime — when the runtime process either crashes during Program.Main or exits before binding to its listening port. IIS sees the worker process disappear and synthesises the 500.30 response.
The single most useful thing to know: 500.30 always has a more specific error in the logs. The page you see in the browser is just the cover. The fix lives in stdout and stderr from the .NET process.
Step 1 — enable stdout logging in web.config
If you haven't already, this is the single most valuable diagnostic step. Edit your published web.config and set:
<aspNetCore processPath="dotnet" arguments=".\YourApp.dll"
stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess" />
Make sure the logs folder exists and is writable by the IIS application pool identity. Restart the app pool, reproduce the failure, then check .\logs\stdout_*.log for the real exception. Don't leave stdoutLogEnabled="true" on permanently — it has performance overhead and will fill disk space over time. Use it to capture the failure, then turn it back off.
Where to find logs on Adaptive Web Hosting
On Adaptive Web Hosting's ASP.NET Core plans, the Plesk file manager gives you direct access to the logs folder inside your site root. You can also enable Plesk's built-in IIS log viewer to see request-level failures alongside your stdout output.
Step 2 — check the .NET runtime version
The most frequent root cause: the runtime version your app targets isn't installed on the host. If your .csproj reads <TargetFramework>net10.0</TargetFramework> but the server only has the .NET 8 runtime, the worker crashes immediately with a "framework not found" exception.
On the server, run:
dotnet --list-runtimes
You should see your target runtime in the list as Microsoft.AspNetCore.App 10.x.x. If not, install the matching ASP.NET Core Runtime — not just the .NET Runtime, which lacks the ASP.NET-specific assemblies. On Adaptive Web Hosting plans, every supported runtime (.NET 8 LTS and .NET 10 LTS) is pre-installed side-by-side, so this failure mode is rare here. But if you're targeting .NET 7 (which reached end-of-life in May 2024), you may need to upgrade your target framework before the app will start at all on a current host.
Step 3 — the “in-process vs out-of-process” mismatch
If your web.config sets hostingModel="inprocess" but your project file declares <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel> (or vice versa), startup will fail with a contradictory configuration error.
The mismatch usually appears when you publish from Visual Studio with one hosting model and then deploy via MSBuild or GitHub Actions with another. Pick one and align both files:
In-process — faster, lower latency, recommended for production. The .NET runtime is loaded directly into the IIS worker process (w3wp.exe).
Out-of-process — .NET runs in its own dotnet.exe process, IIS reverse-proxies via Kestrel. Useful when you need IIS modules and ASP.NET Core to coexist with different bitness.
For 95% of greenfield ASP.NET Core apps on Windows hosting, in-process is correct. The official ASP.NET Core Module reference from Microsoft has the full configuration matrix.
Step 4 — missing or wrong appsettings.json values
If your Program.cs reads configuration eagerly — for example, builder.Configuration.GetConnectionString("Default") followed by a .Replace(...) — and the expected key isn't present in appsettings.json or in environment variables, you get a NullReferenceException during startup. Game over: 500.30.
Common offenders:
Connection strings copied from a developer machine that reference (localdb) instead of the production SQL Server 2022 instance
Strongly-typed configuration sections (builder.Services.Configure<Foo>(...)) where Foo has a required property not present in appsettings.Production.json
Environment-specific files that weren't copied during publish — check that appsettings.Production.json exists in the deployed folder
Step 5 — the app pool identity lacks file permissions
By default, IIS application pools run as IIS APPPOOL\YourPoolName. If the deployment uploaded files as a different account (especially via FTP), the app pool identity might not have read access to the published DLLs or write access to log directories.
On Adaptive Web Hosting, the Plesk for Windows control panel manages permissions automatically as long as you deploy via Plesk's file manager, Web Deploy, or FTP through your hosting account. If you're seeing permission failures, the first thing to check is who owns the files:
icacls "C:\inetpub\wwwroot\yoursite" /T
You should see IIS_IUSRS:(OI)(CI)(RX) or similar read-access entries. If the app pool identity is missing entirely, re-deploy through Plesk to fix the ACLs.
Step 6 — database connection blocking startup
Many production apps run database migrations during startup (app.Services.GetRequiredService<MyDbContext>().Database.Migrate()). If the SQL Server connection times out or the user account doesn't have db_owner on the target database, startup blocks for ~30 seconds and then throws — IIS sees the worker hang and kills it with 500.30.
Diagnostic checklist:
From the server, can you open a SQL Server Management Studio connection with the same credentials your appsettings.json uses?
Is the database in single-user or recovery mode? Run ALTER DATABASE [name] SET MULTI_USER if so.
Does the connection string have Connect Timeout=30? Increase to 60 if your database is large enough that initial migration takes a while.
For production apps on Adaptive Web Hosting plans, every tier includes a real SQL Server 2022 instance (not Express), so connection-pool exhaustion and lightweight-edition limits aren't typical 500.30 causes here.
Step 7 — the DLL load failure (mixed bitness or missing native dependency)
If your project pulls in a NuGet package that includes a native DLL (SQL Server SqlClient, Sentry, image libraries like SkiaSharp), and the app pool's bitness doesn't match the native binary's, startup throws BadImageFormatException during JIT compilation.
Two ways this happens:
App pool is set to 32-bit, but your native dependency is x64-only
You published with <RuntimeIdentifier>win-x64</RuntimeIdentifier> but the app pool runs 32-bit Application Pool defaults
In Plesk for Windows, change the app pool's Enable 32-Bit Applications setting and recycle. Adaptive Web Hosting's plans default to 64-bit because that's what every modern .NET 8/10 LTS workload expects.
Step 8 — a third-party startup task crashed silently
If your Program.cs registers an IHostedService that throws during StartAsync, the host crashes with a BackgroundService failed error during boot. The stdout log will identify the failing service by class name.
Common offenders: services that try to connect to external APIs (Stripe, SendGrid, Azure Service Bus) during startup. If the API key is wrong or the network is unreachable, your app won't even bind to its port. Defensive pattern: move external connection setup into the first request handler instead of StartAsync, or wrap the throw in a logged-and-swallowed exception so the app at least starts.
The diagnostic order I'd actually follow
If I'm dropped onto a server with no context and a 500.30, here's the order that resolves the issue fastest:
Enable stdoutLogEnabled="true" in web.config and reproduce
Read the actual exception from logs/stdout_*.log — this answers 80% of cases
If “framework not found,” check dotnet --list-runtimes against the project's TargetFramework
If “connection failed,” check SQL Server reachability and credentials
If “BadImageFormatException,” check 32-bit/64-bit app pool setting
If config exceptions, diff your appsettings.Production.json against what the app expects
If you've worked through all of the above and the app still won't start, the most likely remaining issue is a custom IHostedService or third-party middleware throwing during pipeline construction. Comment out one-by-one to isolate.
Frequently asked questions
What's the difference between HTTP 500.30 and HTTP 502.5?
HTTP 502.5 ("ANCM Out-Of-Process Startup Failure") is the equivalent of 500.30 for the out-of-process hosting model. The diagnostic steps are identical — enable stdout logging and read the underlying exception. 500.30 is in-process, 502.5 is out-of-process.
Why does the page say "ASP.NET Core app failed to start" but the app worked locally?
Almost always one of three things: the production server lacks the runtime version your .csproj targets, your appsettings.Production.json references resources (databases, file paths, API keys) that exist only on your dev machine, or a NuGet package needs native libraries that aren't on the host. The stdout log identifies which.
Can I get more detailed error pages in production?
Yes — for transient diagnosis. Set the environment variable ASPNETCORE_ENVIRONMENT=Development and Developer Exception Page middleware will surface full stack traces. Never leave this on for production users — stack traces leak code paths, file paths, and sometimes connection strings.
Does Adaptive Web Hosting provide error log access?
Yes. The Plesk for Windows control panel gives direct file-manager access to your site's logs folder, plus a built-in IIS log viewer showing request-level failures. Every plan includes 24/7 ticket support if you need help interpreting the logs.
Are .NET 10 LTS apps any easier to diagnose?
Yes — .NET 10 improved the ASP.NET Core Module's error messages significantly. If you're still on .NET 7 or earlier, upgrading to .NET 10 LTS alone often surfaces the underlying cause that the older 500.30 page was masking.
Production hosting that makes startup failures rare
Most 500.30 issues we see on shared hosting come from environments where the runtime version is wrong, the SQL Server is undersized or shared, or file permissions are inconsistent. Adaptive Web Hosting's ASP.NET Core plans address each of these directly:
All current LTS runtimes pre-installed — .NET 8 LTS and .NET 10 LTS available side-by-side on every plan, so a runtime mismatch never causes startup failures
Real Microsoft SQL Server 2022 — not Express, not shared, so migrations and connection pools behave like production
Dedicated IIS Application Pools — your worker process never competes with neighbour tenants
Plesk for Windows — managed permissions, IIS log viewer, deployment automation, all in one control panel
Every plan includes a 30-day money-back guarantee. View the plan options or talk to an ASP.NET expert.