Troubleshooting HTTP 400 errors in IIS

Applies to:   Internet Information Services

This article describes the troubleshooting steps to identify the cause of various HTTP 400 errors when using IIS.

Overview

After sending an HTTP request to an IIS server, an HTTP client (such as Internet Explorer) may display the following type of error message:


HTTP 400 The webpage cannot be found.

Most likely causes:

  • There might be a typing error in the address.
  • If you clicked on a link, it may be out of date.

What you can try:

  • Retype the address.
  • Go back to the previous page.
  • Go to Bing and look for the information you want.

If the HTTP client is Internet Explorer, and the Show Friendly HTTP Error Messages option is turned off, the error may resemble:

Bad Request

In these scenarios, IIS has rejected the client's HTTP request because the request didn't meet the server's HTTP parsing rules, or it exceeded time limits, or failed some other rule that IIS or HTTP.sys require incoming requests to adhere to. IIS sends the "HTTP 400 - Bad Request" status back to the client, and then terminates the TCP connection.

Tools

Troubleshooting methods

When troubleshooting an HTTP 400 condition, it's important to remember that the underlying problem is that the client has sent a request to IIS that breaks one or more rules that HTTP.sys is enforcing. With that in mind, you'll want to see what exactly the client is sending to IIS. To do it, capture a network trace of the client sending the bad request. You can analyze the trace to see the raw data that the client sends to IIS, and to see the raw response data that IIS sends back to the client. You can also use an HTTP sniffer tool called Fiddler, a great tool as it allows you to see the HTTP headers even if the client and server are communicating over SSL.

The next data item you use is the C:\Windows\System32\LogFiles\HTTPERR\httperr.log file. Beginning in IIS 6.0, the HTTP.sys component handles incoming HTTP requests before they're passed along to IIS, and is the component responsible for blocking requests that don't meet the IIS requirements. When HTTP.sys blocks the request, it logs information to its httperr.log file concerning the bad request and why it was blocked.

NOTE: For more information on the HTTP API error logging that HTTP.sys provides, see Error logging in HTTP API.

It's technically possible, although not very likely, that a client may receive an HTTP 400 response, which doesn't have an associated log entry in the httperr.log. It could happen if an ISAPI filter or extension or an HTTP module in IIS sets the 400 status, in which case you could look at the IIS log for more information. It could also happen if an entity between the client and the server, such as a proxy server or other network device, intercepts a response from IIS and overrides it with its own 400 status and/or "Bad Request" error.

Sample scenario

Following is an example of an HTTP 400 scenario, where a client sends a bad request to IIS and the server sends back an "HTTP 400 - Bad Request" message.

When the client sends its request, the browser error it gets back looks like:

Bad Request (Header Field Too Long)

Capturing a network trace of the request and response, you see the following outputs:

REQUEST:

HTTP: GET Request from Client
HTTP: Request Method =GET
HTTP: Uniform Resource Identifier =/1234567890123456789012345678901234567890/time.asp
HTTP: Protocol Version =HTTP/1.1
HTTP: Accept-Language =en-us
HTTP: UA-cpu =x86
HTTP: Accept-Encoding =gzip, deflate
HTTP: Host =iisserver
HTTP: Connection =Keep-Alive
HTTP: Data: Number of data bytes remaining = 14 (0x000E)

RESPONSE:

HTTP: Response to Client; HTTP/1.1; Status Code = 400 - Bad Request
HTTP: Protocol Version =HTTP/1.1
HTTP: Status Code = Bad Request
HTTP: Reason =Bad Request
HTTP: Content-Type =text/html
HTTP: Date =Wed, 14 Nov 2012 20:36:36 GMT
HTTP: Connection =close
HTTP: Content-Length =44
HTTP: Data: Number of data bytes remaining = 63 (0x003F)

You notice that the response headers don't tell as much as the error message in the browser. However, if you look at the raw data in the response body, you see more:

00000030                                           48 54               HT
00000040 54 50 2F 31 2E 31 20 34 30 30 20 42 61 64 20 52 TP/1.1.400.Bad.R
00000050 65 71 75 65 73 74 0D 0A 43 6F 6E 74 65 6E 74 2D equest..Content-
00000060 54 79 70 65 3A 20 74 65 78 74 2F 68 74 6D 6C 0D Type:.text/html.
00000070 0A 44 61 74 65 3A 20 57 65 64 2C 20 32 38 20 4A .Date:.Wed,.28.J
00000080 61 6E 20 32 30 30 39 20 32 30 3A 33 36 3A 33 36 an.2009.20:36:36
00000090 20 47 4D 54 0D 0A 43 6F 6E 6E 65 63 74 69 6F 6E .GMT..Connection
000000A0 3A 20 63 6C 6F 73 65 0D 0A 43 6F 6E 74 65 6E 74 :.close..Content
000000B0 2D 4C 65 6E 67 74 68 3A 20 34 34 0D 0A 0D 0A 3C -Length:.44....<
000000C0 68 31 3E 42 61 64 20 52 65 71 75 65 73 74 20 28 h1>Bad.Request.(
000000D0 48 65 61 64 65 72 20 46 69 65 6C 64 20 54 6F 6F Header.Field.Too
000000E0 20 4C 6F 6E 67 29 3C 2F 68 31 3E 01 02 03 04 05 .Long).....
000000F0 05 06 0E 94 63 D6 68 37 1B 8C 16 FE 3F D5       ....c.h7....?.

You can see that the error message text displayed in the browser is also viewable in the raw response data in the network trace.

The next step is to look at the httperr.log file in the C:\Windows\System32\LogFiles\HTTPERR directory for the entry that corresponds to the bad request:

#Software: Microsoft HTTP API 1.0
#Version: 1.0
#Date: 2012-11-14 20:35:02
#Fields: date time cs-version cs-method cs-uri sc-status s-reason 
2012-11-14 20:36:36 HTTP/1.1 GET /1234567890/time.asp 400 FieldLength

In this scenario, the Reason field in the httperr.log file provides the exact information you need to diagnose the problem. You see that HTTP.sys logged FieldLength as the reason phrase for this request's failure. Once you know the reason phrase, check the table in Kinds of errors that the HTTP API logs section to get its description:

FieldLength: A field length limit was exceeded.

So at this point you know from the browser error message and the HTTP API error logging that the request contained data in one of its HTTP headers that exceeded the allowable length limits. For this example, the HTTP: Uniform Resource Identifier header is purposefully long: /1234567890123456789012345678901234567890/time.asp.

The final stage of troubleshooting this example is to check the HTTP.sys registry keys and default settings for IIS

Since you know the reason phrase and error are suggesting a header field length exceeding limits, you can narrow our search in the Registry Keys table as such. The prime candidate here is:

Registry key Default value Valid value range Registry key function WARNING code
MaxFieldLength 16384 64 - 65534 (64k - 2) bytes Sets an upper limit for each header. See MaxRequestBytes. This limit translates to approximately 32k characters for a URL. 1

To reproduce this error for this example, the MaxFieldLength registry key was set with a value of 2. Since the requested URL had a HTTP: Uniform Resource Identifier header field with more than two characters, the request was blocked with the FieldLength reason phrase.

Another common HTTP 400 scenario is one where the user making the HTTP request is a member of a large number of Active Directory groups, and the website is configured to user Kerberos authentication. When this occurs, an error message similar to the following will be displayed to the user:

Bad Request (Request Header Too Long)

In this scenario, the authentication token that is included as part of the client's HTTP request is too large and exceeds size limits that http.sys is enforcing. This problem is discussed in detail, along with the solution, in HTTP 400 - Bad Request (Request Header too long) responses to HTTP requests.

References