IIS is logging 200 instead of 404 status code

When you try to access a web page that doesn’t exist, browser shows 404 HTTP status code. However, you may see 200 instead of 404 status code in IIS logs. 

Here is the line from my IIS logs. This is actually a failed request that displayed “404 Page not Found” error to the user.

2018-11-27 17:32:28 ::1 GET /app1/kkrr1 – 80 – ::1 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko – 200 0 0 0

Looking for a way to determine user browsers from IIS logs? Check this post out.

What to do if you see 200 instead of 404 status code

The root cause -in my case- is the custom error configuration in the web.config file. I have the configuration below that redirects users to a custom page when there is a 404 error.

<httpErrors existingResponse="Replace" defaultResponseMode="Redirect" errorMode="Custom">
     <remove statusCode="404"/>
     <error statusCode="404" responseMode="ExecuteURL" path="/index1.htm"/>          

Once I changed ExecuteURL to Redirect in the responseMode attribute, IIS started logging 404 errors.

<httpErrors existingResponse="Replace" defaultResponseMode="Redirect" errorMode="Custom">
     <remove statusCode="404"/>
     <error statusCode="404" responseMode="Redirect" path="/index1.htm"/>          

IIS log that shows the correct status code (404) after the change:

2018-11-27 17:33:25 ::1 GET /app1/oopp – 80 – ::1 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko – 404 0 2 46

200 instead of 404
Incorrect (first line) and correct (second line) status codes


As mentioned in this blog post, responseMode=”ExecuteURL” executes the URL in the custom error configuration sends the response to the user Therefore, IIS logs 200 instead of 404 status code. However, responseMode="Redirect” send 302 response with the custom error page URL to the user. User’s browser makes another request to the given URL.

    – path is treated as URL to execute. Response returned by executing the URL is returned to client as response. On successful child execute, client will see a 200 response. Child request will enter the pipeline in the same worker process. If this request is supposed to be executed by some other application pool, IIS core will generate 403.14. When child execute produce some other error, that error code along with child execute response is returned.
    – If path starts with “http://”, exact URL specified by path is executed. Hostname has to be current hostname. Else server will produce 404.
    – When path starts with “/”, it is assumed as URL for the current site and do a child execute on that.
    – If path doesn’t start with “/” or “http://”, server will produce 404 when trying to execute the URL.

    – Custom error module blindly uses the path as location header value and send a 302 response. If path is set to “/otherpath/otherpage.htm”, this will be used as the destination and most browsers send this request back to the same host. If you set path to www.iis.net, browsers do the right thing and send the new request to www.iis.net instead.
    – IIS doesn’t handle application relative paths both for “Redirect” and “ExecuteURL” as handled by Asp.Net (e.g.  ~/error/404.htm).


Still having the issue?

As a generic solution, adding the line below into the custom error page should solve the issue. Make sure to change the file extension to aspx (For example: 404.aspx).

<% Response.StatusCode = 404; %>

Multiple identical logs in Advanced Logging

Logging two events instead of one is by-design for Advanced Logging extension. Advanced Logging extension subscribes to GENERAL_REQUEST_START event in the pipeline. Whenever this event is called, a new log is recorded.

Check your Failed Request Tracing (FREB) logs. If oyu see that there are child requests, It is expected from Advanced Logging to log more than one records for the same request (More about child requests).

On the other hand, IIS logs works differently. They are based on HTTP.sys kernel driver which creates notifications only when a response is submitted. Therefore, there is one record per request in IIS logs.

Starting with IIS 8.5, Advanced Logging module is no longer available. It was integrated in the logging infrastructure of IIS server. So that this issue won’t happen in IIS 8.5 and newer versions. If you are using IIS 8.0 or a lower version, it is recommended to upgrade it.