How to Fix ASP.NET Core Error 500.30 on Plesk
In this article8 sections
HTTP Error 500.30 means your ASP.NET Core application was found and started, then crashed during startup, almost always because of a wrong connection string, a missing setting or a file it could not read. HTTP Error 500.31 means it never started at all, because the .NET version it was built for is not installed on the server. For 500.30, switch on the stdout log in web.config and read the exception it records. For 500.31, compare the version in your .runtimeconfig.json with the versions the host provides, and either retarget the project or publish it self-contained.
This guide is for ASP.NET Core applications on shared Windows hosting with Plesk and IIS, where you cannot open Event Viewer or log in to the server. Everything below is done with the file manager or FTP and your own build machine.
What the numbers mean
| Error | Meaning | Usual cause |
|---|---|---|
| 500.30 In-Process Start Failure | The app started and threw an exception before it could serve a request | Configuration, connection string, missing file, permissions |
| 500.31 Failed to Find Native Dependencies | The runtime the app targets was not found | App built for a .NET version that is not on the server |
| 500.32 Failed to Load DLL | 32-bit and 64-bit mismatch | App published for win-x86, pool runs 64-bit, or the reverse |
| 500.19 Configuration Error | IIS could not read web.config |
Malformed XML or a section the server does not allow |
| 502.5 Process Failure | Same as 500.30, for out-of-process hosting | Same causes as 500.30 |
| 503 Service Unavailable | The application pool is stopped | Repeated crashes, or the memory limit was reached |
Fixing 500.31: the runtime is missing
On your build machine, open the publish folder and look at the file named after your application ending in .runtimeconfig.json:
{
"runtimeOptions": {
"tfm": "net9.0",
"frameworks": [
{ "name": "Microsoft.NETCore.App", "version": "9.0.0" },
{ "name": "Microsoft.AspNetCore.App", "version": "9.0.0" }
]
}
}
That version must be installed on the server. The major number has to match exactly: an app built for .NET 9 does not run on a server that has only .NET 8. You have two fixes.
Retarget the project to a version the host provides. Change TargetFramework in the .csproj file, for example to net8.0, then rebuild and publish again.
Or publish self-contained, which bundles the runtime with your app so the server’s installed versions no longer matter:
dotnet publish -c Release -r win-x64 --self-contained true -o ./publish
A self-contained publish is larger, around 70 to 100 MB, and you become responsible for republishing when .NET security updates are released. Prefer the framework-dependent publish when the host has your version:
dotnet publish -c Release -r win-x64 --self-contained false -o ./publish
Fixing 500.30: read what the app said
The browser shows nothing useful on purpose. The real message is the exception your application threw, and the stdout log captures it.
Step 1: Switch on the stdout log
Open web.config in the site’s root folder and change the aspNetCore line so logging is enabled:
<aspNetCore processPath="dotnet" arguments=".\MyApp.dll"
stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout"
hostingModel="inprocess" />
Then create a folder named logs next to web.config and make sure the application pool user can write to it. This is the step people miss. The module can only create the folder itself if it is allowed to write to the site’s root, which is often not the case on shared hosting, and when it cannot write, no log appears and no error tells you why.
Step 2: Load the site once and read the log
Request any page, then open the newest file in logs. It contains the startup output and the exception with its stack trace. The first lines usually name the problem outright:
Unhandled exception. Microsoft.Data.SqlClient.SqlException (0x80131904):
Login failed for user 'shop_user'.
at Program.<Main>$(String[] args) in Program.cs:line 24
Step 3: Match it to a cause
| The log says | Fix |
|---|---|
Login failed for user or Cannot open database |
Correct the connection string: server name, database name, user and password as shown in Plesk’s database section |
A network-related or instance-specific error |
The connection string still points at localhost, (localdb) or your development machine |
Could not find file or FileNotFoundException |
The publish was incomplete. Upload the whole publish folder again |
Access to the path ... is denied |
The app writes to a folder it has no permission for. Write to a dedicated folder such as App_Data and give the application pool user write permission on it in Plesk |
Value cannot be null (Parameter 'connectionString') |
A setting exists on your machine only (user secrets or an environment variable). Add it to appsettings.Production.json or to web.config |
| The log is empty or absent | The logs folder is missing or not writable, or the app is failing before .NET starts: check for 500.31 instead |
Step 4: Settings that differ between your machine and the server
On the server the environment is Production unless you say otherwise, so appsettings.Development.json is ignored and user secrets do not exist. Anything your app needs at startup must be in appsettings.json, appsettings.Production.json or web.config:
<aspNetCore processPath="dotnet" arguments=".\MyApp.dll" hostingModel="inprocess">
<environmentVariables>
<environmentVariable name="ConnectionStrings__Default" value="Server=...;Database=...;User Id=...;Password=...;TrustServerCertificate=True" />
</environmentVariables>
</aspNetCore>
Two underscores in the name stand for the colon in ConnectionStrings:Default.
Step 5: Switch the log off again
Set stdoutLogEnabled="false" when the site works. The stdout log has no size limit and no rotation, and on a busy site it fills the disk space of your plan. It can also contain connection details, so delete the files in logs as well.
Warning. Do not set ASPNETCORE_ENVIRONMENT to Development on a live site to see errors in the browser. The developer error page shows source code, settings and stack traces to every visitor. Use the stdout log, which only you can read.
Uploading without “file in use” errors
While the site runs, IIS keeps your DLL files open, so an upload over a running app fails or, worse, half succeeds. Before uploading, place a file named app_offline.htm in the site’s root folder. IIS stops the app and shows that file to visitors. Upload the new publish, then delete app_offline.htm and the app starts with the new files.
When it starts, then stops under load
If the site works after a restart and returns 503 some hours later, the application pool was recycled or stopped. On shared Windows hosting each plan has a memory allocation for its application pool, and an app that grows past it is recycled. Check for the usual leaks: large objects cached in static fields without a size limit, HttpClient created per request instead of through IHttpClientFactory, and whole tables loaded into memory with ToList() where a query would do. If the application simply needs more memory than the plan gives, it needs a larger plan.
Common mistakes to avoid
- Uploading the project folder instead of the publish folder. The server needs the output of
dotnet publish, not your source code. - Forgetting the
logsfolder and its write permission. If the log cannot be written, you get no log and no explanation. - Leaving stdout logging on. It grows until the disk is full.
- Publishing for the wrong architecture. Use
win-x64unless your host tells you the pool is 32-bit. - Editing
web.configby hand and breaking the XML. One missing quote turns 500.30 into 500.19. Keep a copy before you edit. - Relying on user secrets. They exist only on your development machine.
Windows hosting that matches your build
SiteHarbour Windows hosting runs Windows Server 2022 and IIS 10 with Plesk, and provides .NET Core 6, 7, 8, 9 and 10 alongside ASP.NET Framework 4.x, so a framework-dependent publish for any of those versions runs without bundling the runtime. Every site has its own dedicated application pool, and plans include MS SQL databases and a memory allocation from 300 MB to 1.5 GB.
Frequently asked questions
Where are the IIS logs on shared hosting?
You cannot open Event Viewer on a shared server. Plesk shows the site’s web server logs in its Logs section, but the startup exception itself is only in the stdout log described above.
Should I use in-process or out-of-process hosting?
In-process is the default and the faster of the two, because the app runs inside the IIS worker process. Use out-of-process only if you have a specific reason, such as a library that requires it.
The app works locally. Why does it fail on the server?
Almost always configuration: a connection string that points at your own machine, a setting stored in user secrets, or a development-only settings file. The stdout log names the missing piece.
Can I run an older ASP.NET Framework site on the same plan?
Yes. ASP.NET Framework 4.x sites run under IIS directly and do not use the ASP.NET Core module, so none of these error codes apply to them.
Do I need to restart the site after changing web.config?
No. IIS notices the change to web.config and restarts the application by itself on the next request.
The short version: 500.31 is a version problem, solved by retargeting or publishing self-contained. 500.30 is your application’s own exception, and the stdout log, written to a logs folder the app is allowed to write to, tells you which one.