HTTP Status: Client Errors

The last post in my HTTP status code series was just over six months ago. I’m sorry for taking so long to revive the series, but I’m back with a discussion about the 4xx status codes. I hope you enjoy it!

The 4xx series of HTTP status codes is intended for client errors. That is, the server determines that there is an error occurring as a result of bad or missing data in the request from the client. The 404 Not Found status code is the most recognizable of these, and it’s the server’s way of telling the client that the requested URI is not available on the server. This is not the server’s fault, but, rather, it is the client’s, so the server responds saying, “Sorry, pal! I can’t find what you’re looking for.”

In an earlier post, I mentioned the 100 Continue status code. I mention it again here because the use of an Expect: 100-continue request header in a “look-before-you-leap” (LBYL) request can be useful to let you know of potential problems with your request before you receive any of these status code responses from the server.

Let’s use the same request from the 100 Continue post as an example:

POST /content/videos HTTP/1.1
Content-Type: video/mp4
Content-Length: 105910000
Authorization: Basic bWFkZTp5b3VfbG9vaw==

Note that this request does not contain the Expect header, and it is assumed that the body of this request contains the full binary content of the video being posted.

For the sake of example, let’s assume that the server doesn’t allow POST requests to the /content/videos URI. If this is the case, then the server should return a 405 Method Not Allowed status code in response to this request. This is a condition that we could have checked for with the LBYL request prior to sending the full 105,910,000 bytes of the video, thus saving bandwidth, client resources, and server resources.

HTTP/1.1 405 Method Not Allowed
Date: Wed, 28 Jan 2009 03:04:25 GMT

In addition, to the 405 Method Not Allowed status, according to RFC 2616, the server must included an Allow header listing the valid methods for the requested resource. Sending the Allow header in response to HEAD requests (and all requests for that matter) can also help inform clients of acceptable methods.

If the server does allow POST requests at this URI but we fail to send the Authorization header with the request, then the server should respond with a 401 Unauthorized status, telling the client to resend the request with proper authorization. The server must include a WWW-Authenticate header in this response to indicate the expected authorization scheme. If the request, however, does include the Authorization header, as illustrated in the example, but the authentication fails for whatever reason, then the server should respond with a 403 Forbidden status and a description with the reason for the failure in the response body.

If the request doesn’t include the Content-Length header, then you might want the server to respond with a 411 Length Required status. Requiring the length and comparing it to the length of the actual request body is a good way to determine whether there was any loss of data. However, if the integrity of data is a concern, you might want to require clients to include the Content-MD5 header in the request. Since there is no status code to indicate Content-MD5 as a requirement, simply return a 400 Bad Request status stating your requirement of the Content-MD5 header in the response body.

The 400 Bad Request status code literally means that the “request could not be understood by the server due to malformed syntax,” but it is a generic enough response that it can be used for a variety of other client errors not covered by the other 4xx series status codes. For example, I have used 400 Bad Request as a way to indicate data validation failures in POST and PUT requests.

If the full request reaches the server, but the server determines that the 105,910,000 bytes of the video is beyond the acceptable limit—maybe we want to limit users to 50MB uploads—then respond with 413 Request Entity Too Large because the request body is larger than the server is willing to process. Again, the client could avoid this by using a LBYL request.

Likewise, if the server doesn’t want to support the video/mp4 media type, then it should respond with a 415 Unsupported Media Type status code. A LBYL request would have told us this, as well.

I’ve already discussed 416 Requested Range Not Satisfiable in a post about range requests and 417 Expectation Failed in a post about the 100 Continue status code.

Finally, we are all familiar with the 404 Not Found status code. I mentioned it earlier in this post. The 404 Not Found status, however, doesn’t tell the client whether the condition is temporary or permanent. It’s a pretty generic “I can’t find it” message. If you know that the resource is gone permanently, you may want to return a 410 Gone status code, instead, as a way of letting smart clients (like search engines) know that they should remove all links to the resource. If the resource has moved permanently, though, I recommend using a 301 Moved Permanently status, which will also tell these smart clients to update their links. How you choose to inform clients of the fate of your resources is up to you, but it’s in your best interest to tell them whether the data has moved or is gone and is no longer available.

I also mentioned the 404 Not Found and 410 Gone statuses when discussing the 201 Created and 202 Accepted status codes.