Fix it now
IIS could not build the configuration for that URL, so it refused the request before any code ran. Microsoft publishes nine different HRESULTs under 500.19, and the one on the error page tells you which of them you have. Read that hex value first; everything else follows from it.
%windir%\system32\inetsrv\appcmd list config "Default Web Site/" /section:?
%windir%\system32\inetsrv\appcmd search config "Default Web Site/"
%windir%\system32\inetsrv\appcmd list config "Default Web Site/"
- Read the HRESULT off the 500.19 page.
0x80070021is a section locked at a higher level,0x800700b7a duplicate entry,0x8007007ea reference to a module or DLL that is not there,0x800700c1a module whose bitness does not match the pool, and0x8007010ba content directory that cannot be accessed. - For
0x80070021, unlock the section the error names:%windir%\system32\inetsrv\appcmd unlock config /section:<sectionName>. That is machine-wide, so consider deleting the entry from web.config instead. - For
0x8007010b, check the physical path on the site or application in IIS Manager under Basic Settings: that it exists, is spelled correctly, sits on a valid file system, and carries file-level permissions the site can use. - For an access-denied HRESULT, grant Read to the
IIS_IUSRSgroup on the folder through Properties, Security, Edit, Add. - For 500.21, install the role service or module that provides the handler the mapping names, then run
iisreset.
If you would rather not unlock a section for the whole machine, the documented alternative is a <location path="." overrideMode="Allow"> element in applicationHost.config scoped to the path that needs it.
If the page loads, you are done. If it does not, the next section explains what IIS is doing before it gives up and which layer of the merge failed.
Why it happens
Every request is served against a merged configuration. IIS starts with applicationHost.config at machine level, applies each web.config on the path down to the application, then the one in the requested folder. That merge has to succeed completely before a line of your code is reached. 500.19 is published as “Configuration data is invalid”, and it means the merge stopped.
The useful part is not the 500.19 itself but the HRESULT printed with it. Microsoft publishes nine of them and they point at genuinely different faults: malformed or unrecognised XML, a section locked at a higher level, a UNC or permission problem reaching the file, a duplicate entry inherited from above, a reference to a module or DLL that does not exist, a module whose bitness does not match the application pool, a content directory that cannot be accessed, an identity that cannot open web.config on a remote share, and a physical path that does not match the virtual directory. Diagnosing 500.19 without reading that value is guessing between nine answers.
500.21 is a different failure with a similar feel. It is published as “Module not recognized”: the configuration parsed correctly, and then named a handler whose module is not registered on this server. Classically that is a site mapping requests to the managed pipeline handler on a server where ASP.NET was never added as a role service. The 500.5x codes belong to the URL Rewrite module and mean a rewrite rule failed rather than the configuration as a whole.
The section your web.config sets is locked at a higher level
You have this one if The HRESULT is 0x80070021 and the error names a section such as handlers, modules or windowsAuthentication.
- Decide first whether the site genuinely needs to set that section. Deleting the entry is often the right answer and costs nothing.
- If it does need it, unlock the named section:
%windir%\system32\inetsrv\appcmd unlock config /section:<sectionName> - Find every level that already sets it before you change anything:
%windir%\system32\inetsrv\appcmd search config "<site>/" /section:<sectionName> - Request the page again. Configuration changes apply on the next request.
Unlocking with appcmd is machine-wide. On a shared server that loosens the section for every site on the box, which is why the scoped <location path="." overrideMode="Allow"> form exists.
The configuration references a module or DLL that is not there
You have this one if 0x8007007e in the 500.19 detail, or a 500.21 naming a handler and its module.
- Read the module or DLL name out of the error. It usually names the feature outright.
- Add the matching IIS role service, or install the standalone module if it is an add-on such as URL Rewrite.
- If the product it belonged to has been uninstalled, remove the entry that references it instead.
- Enable Failed Request Tracing if the error does not name the reference; Microsoft documents it as the way to find which one is wrong.
- Run
iisresetafter adding or removing a native module.
The module and the application pool disagree on bitness
You have this one if 0x800700c1, and the site uses a component that was built for one architecture on a pool running the other.
- Open the application pool’s Advanced Settings in IIS Manager and read Enable 32-Bit Applications.
- Match it to the module: a 32-bit component needs the setting True, a 64-bit one needs it False.
- If the module is not yours to rebuild, give it a pool of its own at the right bitness rather than changing a shared pool.
- Recycle the pool and retry.
Microsoft lists a corrupted module as the other reading of this HRESULT, so if the bitness is already right, reinstall the component before changing anything else.
The physical path or the file cannot be read
You have this one if 0x8007010b, 0x80070005, 0x8007052e or 0x80070003, and the path in the error looks wrong, empty or remote.
- In IIS Manager select the site or application, open Basic Settings, and check the physical path character by character.
- Grant Read to
IIS_IUSRSon the folder through Properties, Security, Edit, Add. - If the content is on a UNC share, do not use pass-through authentication: Microsoft’s documented remedy is to specify a user account with the right permissions under Connect as.
- If the path looks correct and it still fails, collect a Process Monitor trace. Microsoft names it as the way to see which file access is actually being refused.
Full reference
The nine HRESULTs, and what each one is actually telling you
| HRESULT | What Microsoft publishes | Where to start |
|---|---|---|
0x8007000d |
Malformed or unrecognised XML element, or a module such as URL Rewrite is not installed | Delete the element, or install the module |
0x80070021 |
The named section is locked at a higher configuration level | Unlock it, or stop setting it at this level |
0x80070005 |
UNC pass-through authentication, or IIS_IUSRS lacks permission on the configuration or the directory | Use a named account for the share, or grant Read to IIS_IUSRS |
0x800700b7 |
A duplicate entry for the section setting exists higher in the hierarchy | Remove or rename the duplicate |
0x8007007e |
The configuration references an invalid or non-existent module or DLL | Remove the reference, or install what it names |
0x800700c1 |
The module’s bitness differs from the application pool, or the module is corrupted | Match the pool, or reinstall the module |
0x8007010b |
The specified content directory cannot be accessed | Check the path exists, is named correctly and is readable |
0x8007052e |
The default process identity cannot open web.config on a remote share | Give the pool identity rights to the share |
0x80070003 |
Permissions, a path mismatch, or no web.config under the application root | Check the path and its permissions |
Reading the configuration instead of guessing at it
| Command | What it gives you |
|---|---|
appcmd list config "<site>/" |
The effective merged configuration for that level |
appcmd list config "<site>/" /section:<name> |
One section of it |
appcmd list config /section:? |
The list of section names, which is how you get the spelling right |
appcmd search config "<site>/" |
Every location that defines configuration under that path |
appcmd search config "<site>/" /section:<name> |
Every location that sets one section, which finds duplicates |
appcmd unlock config /section:<name> |
Unlocks a section machine-wide so lower levels may override it |
appcmd lock config /section:<name> |
Puts it back |
All of these live in %windir%\system32\inetsrv, which is not on the path by default, so call appcmd by its full path or change into that directory first.
Locking, and the narrower way to open it
Locking is expressed in configuration rather than only through appcmd. A section is unlocked for a path by wrapping it in a <location> element with overrideMode="Allow", and locked with overrideMode="Deny", which is the default for most IIS sections. Individual attributes and elements can be pinned inside an unlocked section with lockAttributes, lockElements, lockAllAttributesExcept, lockAllElementsExcept and lockItem.
That matters on a shared server. appcmd unlock config opens the section for every application on the machine. A <location> element with a real path in it opens it for one. If you are unlocking a security-relevant section such as windowsAuthentication, use the narrower form, and question whether the site should be setting it at all.
The URL Rewrite codes
| Status | Published meaning |
|---|---|
500.50 |
A rewrite error during RQ_BEGIN_REQUEST handling: a configuration or inbound rule execution error |
500.52 |
A rewrite error during RQ_SEND_RESPONSE handling: an outbound rule execution |
500.53 |
A rewrite error during RQ_RELEASE_REQUEST_STATE handling: an outbound rule set to run before the output user cache is updated |
The difference between 500.52 and 500.53 is which stage the outbound rule was configured to run at, not how late the failure was. If you are looking at a 500.53, the rule has preCondition behaviour that puts it ahead of the output cache update, and that is the part to examine.
When the detail is not on the page
- Enable Failed Request Tracing for status 500 and read the trace. Microsoft names it as the way to identify an incorrect module or DLL reference when the error text does not.
- Collect a Process Monitor trace for the file access failures. It is the documented route for 0x8007010b and 0x80070003, where the path in the error looks fine and the access still fails.
- Compare the merged configuration with
appcmd list configagainst a server where the site works. The file is not portable on its own; the server configuration it depends on has to travel with it. - Check the IIS log for the request and confirm the sc-status and sc-substatus you think you are getting.
Every code this article covers
| Code | What it points at | Source |
|---|---|---|
HTTP 500.19 |
Configuration data is invalid: IIS could not read or apply the configuration for the requested path | Microsoft Learn |
HTTP 500.21 |
Module not recognized: a handler mapping names a module that is not registered on this server | Microsoft Learn |
HTTP 500.0 |
Module or ISAPI error occurred, after configuration succeeded. ASP.NET Core publishes the same status separately as an in-process handler load failure | Microsoft Learn |
0x8007010B |
One of the nine HRESULTs published under 500.19: the specified content directory cannot be accessed | Microsoft Learn |
HTTP 500.50 |
A rewrite error during RQ_BEGIN_REQUEST handling: a configuration or inbound rule execution error | Microsoft Learn |
HTTP 500.52 |
A rewrite error during RQ_SEND_RESPONSE handling: an outbound rule execution | Microsoft Learn |
HTTP 500.53 |
A rewrite error during RQ_RELEASE_REQUEST_STATE handling, for an outbound rule configured to run before the output user cache is updated | Microsoft Learn |
Confirm the fix worked
- Request the previously failing URL and confirm it returns the page rather than an error.
- Request it from a remote client as well as from the server console.
- Run
appcmd list config "<site>/"and confirm the merged configuration holds what you expected and nothing you did not. - If you unlocked a section, run
appcmd search config "<site>/" /section:<name>and confirm nothing else on the box has started overriding it. - Check the IIS log for that request: sc-status 200 with sc-substatus 0.
Questions people ask about this
Does fixing this cost anything?
No. Every cause here is configuration, a permission, or a missing feature, and every fix uses tools already on Windows Server. No licence changes anything about a 500.19.
Why does the same web.config work on my development machine?
Because that machine has more sections unlocked and more modules installed. Two of Microsoft’s published HRESULTs for 500.19 are exactly this: a locked section, and a reference to a module that is not present. The file depends on server configuration that has to travel with it.
Do I need to restart IIS after editing web.config?
No. IIS applies the change on the next request. A restart is needed when you install a native module or change applicationHost.config in a way that affects the service.
Is it safe to unlock every section?
No. appcmd unlock config is machine-wide and lets any site override settings the administrator meant to fix. Unlock only the section the error names, and prefer the scoped <location path="..." overrideMode="Allow"> form on a server with more than one site on it.
I get a bare 500 with no HRESULT at all. Now what?
Turn on Failed Request Tracing for status 500 and request the page once. Microsoft documents it as the way to get the detail when the error page does not carry it, and it will name the module or reference that failed.
