120

I'm wondering if it is correct to return HTTP 200 OK when an error occurred on the server side (the error details would be contained inside the response body).

Example:

  1. We're sending HTTP GET
  2. Something unexpected happened on the server side.
  3. Server returns HTTP 200 OK status code with error inside a response (e.g. {"status":"some error occurred"})

Is this the correct behavior or not? Should we change the status code to something else than 200?

Raf
  • 88
  • 1
  • 11
krzakov
  • 3,871
  • 11
  • 37
  • 52
  • 26
    HTTP 200 means transmission is OK on the http level. This has nothing to do with success or failure of your "business code". In this case the HTTP 200 indicates that your "business code error message" was succesfully transferred ;-) Alternatively you could let your server respond with HTTP 500 meaning "internal error". This is more typical for technical or unrecoverable problems on the server. – geert3 Jan 13 '15 at 11:57
  • 1
    Can anybody confirm that? I talked with some programmers and I can hear different opinions. – krzakov Jan 13 '15 at 12:01
  • 3
    Please use code 412 instead. – Dima Tisnek Nov 23 '17 at 02:29
  • 12
    Looking at the two conflicting answers this exactly why Stack Overflow should be more encouraging of discussion. – wobbily_col Apr 12 '18 at 09:16
  • 2
    The way I see it is based on the expected intent. If the caller expects a true or false, it is a business response and both true and false should be sent back as a 200. On the other if there is an API that say handles Deletion of an Order - the call to this API expects the Order to already exist. In the event it doesn't, then a 404 makes sense here and not 200. So it's not a one answer fit all kind of situation. – MovieMe Nov 19 '20 at 17:23
  • 1
    HTTP codes have meaning to clients, like "(don't) cache this response" or "try again after {interval}." These should be considered when picking your status codes. In general, an _error_ (exception, crash, whatever) should be a 5xx whether it came from business code or not. Cf. a request that can't be fulfilled when everything goes right _can_ be a 2xx w/ error message. Depends on how you want the client to react, though; you _could_ use a 503 for a non-exception failure if you want a client to have the ability to retry automatically after an interval that you control. – pyansharp Aug 30 '21 at 14:56
  • You are asking if failures are "OK". Are you okay? – doug65536 Nov 01 '21 at 06:50

8 Answers8

177

No, it's very incorrect to send 200 with a error body

HTTP is an application protocol. 200 implies that the response contains a payload that represents the status of the requested resource. An error message usually is not a representation of that resource.

If something goes wrong while processing GET, the right status code is 4xx ("you messed up") or 5xx ("I messed up").

mfaani
  • 33,269
  • 19
  • 164
  • 293
Julian Reschke
  • 40,156
  • 8
  • 95
  • 98
  • So basically You agree with previous answer? – krzakov Jan 13 '15 at 14:44
  • 18
    No, I disagree completely with the first part that claims that it would be ok to return 200. – Julian Reschke Jan 13 '15 at 15:02
  • 1
    I'm totally confused. Two completely different explanations. – krzakov Jan 14 '15 at 08:28
  • 1
    Please see my comment on the other answer. – geert3 Jan 14 '15 at 08:48
  • 2
    What I think 200 OK error can be appropriate on some cases. But in this case client makes GET request ask some resources dont get that resource client was asking for, but gets something else this is wrong. If it is Server error 5XX if client side 4XX e.g the resource that was asked does't exists 404. My opinion. – FrAn Jan 14 '15 at 09:09
  • 1
    Also updated my answer to elaborate a bit more about use cases of either 200, 4xx and 5xx. – geert3 Jan 14 '15 at 09:14
  • 1
    But what status code should be returned in case there are no seats in aircraft then? – Alexanderius Feb 24 '16 at 02:17
  • Last time i checked, aircrafts usually don't implement HTTP @Alexanderius :P – vestol Mar 12 '17 at 20:08
  • 19
    After having recent experience with a very large fortune 500 eCommerce site, I have to disagree with this answer implying to not use 200 for errors. This company in particular returns everything as 200 OK. All the errors that can be handled by Spring Java are returned as 200, and in the body you'll have an errors property available. Simple as that. No need to try to figure out what error belongs to what obscure HTTP code. – prograhammer Mar 21 '17 at 06:59
  • Completely agree with this answer. As a counter example to the Google and Facebook examples, in the Microsoft Azure REST API documentation, they list several errors that have nothing to do with the HTTP layer itself that result in a 400 response. https://learn.microsoft.com/en-us/rest/api/storageservices/common-rest-api-error-codes – harperska May 19 '17 at 16:58
  • 1
    When you do a GET and receive a 200, that means you should be able to presume that the content of the response body is the resource itself you are looking for. In the question, they say that something unexpected happened on the server side, presumably meaning that the intended resource will not be returned in the response body. This is exactly the use case to return a 5xx corresponding to exactly what unexpected server side error occurred. – harperska May 19 '17 at 17:06
  • Additionally, while the original question is about a GET request specifically, in the case of a POST request, a 2xx indicates that you should be able to presume that your resource has been successfully created. Validation errors would preclude this, and therefore you should get back a 4xx (probably a 400) indicating that your POSTed data has failed validation. – harperska May 19 '17 at 17:07
  • 13
    "HTTP is an application protocol." Well, while [wikipedia agrees](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) with this definition, it must be said that here **application** is referring to the [IP Application Layer](https://en.wikipedia.org/wiki/Application_layer) -- which wikipedia lists the likes of HTTP, Telnet, FTP and SSH -- all _applications_ of IP communications. This is **not** the same as my application / business logic, which uses said communications. Thus, sending an HTTP 200 with an application-specific error message is quite reasonable. – Jeff Ward Feb 15 '19 at 22:58
  • 1
    This doesn't take into account when you need to act on errors that are not related to communications. I.E: Credit Card denied by XXXX There is no protocol for this hence the need of custom objects that might define an action. – NSPunk Nov 12 '19 at 12:01
  • @NSPunk - what about 424 in this case - https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/424 (yeah I know its 4 years later but this discussion is great) – hi_my_name_is Apr 07 '23 at 10:06
  • Seems like there's no consensus on if a server error response should be 200 or 500, which is pretty bad for something that's supposed to be a clear convention like HTTP. Regardless of what the correct choice is, if many people are doing something different, the whole point of a protocol is failing. – Juan Perez Jun 06 '23 at 11:03
  • This is not a matter of opinion. The specs are clear. If somebody sends an error response as "200 OK", he/she's doing it wrong. See . – Julian Reschke Jun 06 '23 at 16:46
80

HTTP status codes say something about the HTTP protocol. HTTP 200 means transmission is OK on the HTTP level (i.e request was technically OK and server was able to respond properly). See this wiki page for a list of all codes and their meaning.

HTTP 200 has nothing to do with success or failure of your "business code". In your example the HTTP 200 is an acceptable status to indicate that your "business code error message" was successfully transferred, provided that no technical issues prevented the business logic to run properly.

Alternatively you could let your server respond with HTTP 5xx if technical or unrecoverable problems happened on the server. Or HTTP 4xx if the incoming request had issues (e.g. wrong parameters, unexpected HTTP method...) Again, these all indicate technical errors, whereas HTTP 200 indicates NO technical errors, but makes no guarantee about business logic errors.

To summarize: YES it is valid to send error messages (for non-technical issues) in your http response together with HTTP status 200. Whether this applies to your case is up to you. If for instance the client is asking for a file that isn't there, that would be more like a 404. If there is a misconfiguration on the server that might be a 500. If client asks for a seat on a plane that is booked full, that would be 200 and your "implementation" will dictate how to recognise/handle this (e.g. JSON block with a { "booking": "failed" })

geert3
  • 7,086
  • 1
  • 33
  • 49
  • 15
    See. HTTP status codes are technical responses, NOT business logic responses. I can very well imagine a HTTP/REST API where HTTP 200 is returned for obviously failing business logic. For instance: I am a HTTP client booking a flight on a plane. All my parameters are OK, technically no reason for HTTP 4xx. Server is healthy, no HTTP 5xx. Yet the plane is full. The response is a block of JSON explaining that fact: `{"booking":"failed","reason":"plane is full"}`. It is perfectly OK for this to get a HTTP 200, in fact (IMHO) this would be the ONLY valid HTTP status code. – geert3 Jan 14 '15 at 08:48
  • 46
    _"HTTP 200 has nothing to do with success or failure of your "business code"_ - yes, it does. HTTP is an application protocol, its status codes reflect that. See [RFC 7231, section 6](https://tools.ietf.org/html/rfc7231#section-6): _"The status-code element is a three-digit integer code giving the result of the attempt to **understand and satisfy** the request"_, "satisfy" being a successful processing of the request. If at any point in the application an _error_ occurs (whether trying to book a seat on a full flight is an error is another discussion), you should not return a 2xx status code. – CodeCaster Jan 14 '15 at 09:28
  • 18
    Have a look at the 4xx and 5xx codes. They are clearly intended for technical issues, and "understand and satisfy the request" should be taken in this sense. Server cannot understand the request if it has an unsupported media type (415) or the method is not allowed (405). Server cannot satisfy a request if bandwidth limit is exceeded (509) or there was a network read timeout (598). But booking a seat on a full plane has nothing to do with these issues and here the request was technically understood and satisfied even though the plane is full, ergo: HTTP 200. – geert3 Jan 14 '15 at 09:48
  • 20
    To prove my point with a practical example. The Google Maps REST API. https://developers.google.com/maps/documentation/directions/#sample-response All status codes and error messages are returned in JSON/XML blocks, but in each case HTTP 200 is returned on the HTTP level. – geert3 Jan 14 '15 at 09:58
  • 5
    That Google abuses the HTTP protocol does not make it right. Each of those "status codes" has an appropriate HTTP equivalent, and only for OK they should return 200. – CodeCaster Jan 14 '15 at 10:00
  • 3
    That you contradict one of the most widely used practical REST APIs developed by the largest internet company, doesn't make your statement right, I would say to the contrary. Again: they rightfully return HTTP 200 because the HTTP protocol **didn't** fail. Some of the underlying business logic failed, so they comminicate that via XML inside a HTTP 200'ed response. Granted some could have been 4xx but they likely chose for consistency in those cases. – geert3 Jan 14 '15 at 10:02
  • 7
    They're returning 200 for INVALID_REQUEST (400), OVER_QUERY_LIMIT (429), REQUEST_DENIED (403) and UNKNOWN_ERROR (500). With REST, you're using HTTP as an application protocol. There's no specification so it's all fuzzy and opinion-based anyway, but your "HTTP status codes are only for the HTTP level" is too rigid. HTTP allows for applications to return status codes as they please, see: _"403 indicates that the server understood the request but refuses to authorize it"_, _"404 indicates the server [..] is not willing to disclose that one exists"_. – CodeCaster Jan 14 '15 at 10:16
  • 2
    @geert3 you have a correct argument but you are missing the point of the original question. _Something unexpected_ happened on the server side. So the correct response would be a 5xx response. – radixhound Oct 13 '16 at 22:16
  • 14
    Interestingly I tried to edit my comment because I accidentally submitted it before I was done, and SO responded with a 500 'You can only edit your comment for 5 minutes'. So even though my submission was 'successful' and the error was on my side, it responded with 500. ¯\_(ツ)_/¯ I also wanted to support your side of the argument as valid even though for this particular answer it's probably not. – radixhound Oct 13 '16 at 22:31
  • 5
    Facebook Graph API also returns 200 OK for everything. – Sunny Jan 29 '17 at 04:39
  • 2
    I agree with this except `404 NotFound`. It's a bit complicated when returning a not found error: A 404 response is proper when client is requesting a non-exist file, but is it still a proper way when client is searching for something? (For instance, the client is searching books with title "machine learning"). Should server responses a 404 or something like `{ "total": 0 }` ? – Simon. Li Aug 12 '17 at 06:17
  • To me it makes less sense to return an error with a 200. The consumer code will check for an error in the status code. Then if an error has a 200 code, you need to check the content for an error as well. Two checks doing the same thing. – wobbily_col Apr 12 '18 at 11:22
  • 3
    @Simon.Li in fact your example of returning `HTTP 404` to indicate "no matches to your query" is in my opinion a very clear argument _against_ using (technical) HTTP error codes for "business logic" problems. The fact that no books were found is a business problem. Obviously the query results page (although empty) was found, hence `HTTP 200`. – geert3 Apr 12 '18 at 22:15
  • 1
    @CodeCaster If we have to use a different code rather than `200` for the geert3's full plane example, what would be the correct HTTP status code instead of `200`? – tonix Jun 27 '18 at 21:03
  • 1
    @tonix it's a discussion that'll never end, because there is no spec there is no "correct". You could argue for 409 Conflict, for example. – CodeCaster Jun 28 '18 at 07:43
  • @CodeCaster You are right, it seems there isn't a standard rule of thumb. – tonix Jun 28 '18 at 10:55
  • 2
    For those arguing that HTTP is an application protocol, see [my comment above](https://stackoverflow.com/questions/27921537/returning-http-200-ok-with-error-within-response-body#comment96221959_27922900). Summary: The IP "application layer" != my application / business logic. – Jeff Ward Feb 15 '19 at 23:02
  • I find that both sides of this argument have their pros and cons. Perhaps the golden middle way would be to return a HTTP 200 if all went fine, and the generic HTTP 500 with application-specific error details in the body if anything goes wrong? That way the client can easily determine if the request was fulfilled by simple checking for a HTTP 200. If the response is anything other than 200, then the client can start looking at the details of what went wrong (Is it a 403 or a 500? If it's a 500, what is the error message? And so on.). I personally find that the client code is cleaner this way. – Magnus Apr 26 '20 at 18:59
  • So, you say it is fine to send 200 if there are business logic error, in that case, my consuming client would have to implement each `if-else` block to handle the business logic errors. Typically, what should happen is, when there is an error during the API call, the consuming client should handle the error in error handler and all their logic to handle errors would go there. I prefer to return HTTP error codes, if the seat is not available, I would simply return 400 with an explanation so the consuming client can catch the exception and display the message or perhaps customize it. – Jamshaid K. Apr 06 '21 at 07:56
  • Then how do you use some 'intentional error' like 401? Everything is totally OK but the developers intentionally block your request just because they don't let you do this. There's nothing wrong with the transmission. – legenddaniel May 14 '21 at 16:20
  • 1
    I feel its a waste of time trying to decide what the "correct" code is. Since codes aren't consistently used, then you shouldn't expect a certain style. Rather, focus your efforts on documenting your api. – SILENT Jul 08 '21 at 18:21
  • `If client asks for a seat on a plane that is booked full, that would be 200 and your "implementation" will dictate how to recognise/handle this (e.g. JSON block with a { "booking": "failed" })` This is valid, but it's not the kind of situation OP asked about. They said, "something unexpected happens on the server side." That is categorically a 5xx status. A booking failure because of a full plane isn't a failure at all--the app worked exactly as expected. That's a 2xx. If it failed because an upstream, non-local API (eg. the payment processor) failed, back to 5xx. – pyansharp Aug 14 '21 at 06:49
  • @pyansharp that's exactly my point. It depends on whether `{"status":"some error occured"}` represents a business issue (200) or a technical issue (4xx, 5xx...) – geert3 Aug 25 '21 at 14:10
  • Then I guess the argument is really about the boundary between "technical" and "business." IMO, if a client sends a well-formed request but the server has to reject it for a business reason, that should _probably_ be a 400 because otherwise the client may proceed with invalid data on the assumption that 200 means ALL okay. A full plane can be a 200, but maybe the client requests 24 tickets and your app is only allowed to sell 20 at a time for some reason--that's a 400, and has absolutely nothing to do with HTTP at a "technical" level. – pyansharp Oct 05 '21 at 18:11
23

I think these kinds of problems are solved if we think about real life.

Bad Practice:

Example 1:

Darling everything is FINE/OK (HTTP CODE 200) - (Success):
{
  ...but I don't want us to be together anymore!!!... (Error)
  // Then everything isn't OK???
}

Example 2:

You are the best employee (HTTP CODE 200) - (Success):
{
  ...But we cannot continue your contract!!!... (Error)
  // Then everything isn't OK???
}

Good Practices:

 Darling I don't feel good (HTTP CODE 400) - (Error):
{
  ...I no longer feel anything for you, I think the best thing is to separate... (Error)
  // In this case, you are alerting me from the beginning that something is wrong ...
}

This is only my personal opinion, each one can implement it as it is most comfortable or needs.

Note: The idea for this explanation was drawn from a great friend @diosney

14

Even if I want to return a business logic error as HTTP code there is no such acceptable HTTP error code for that errors rather than using HTTP 200 because it will misrepresent the actual error.

So, HTTP 200 will be good for business logic errors. But all errors which are covered by HTTP error codes should use them.

Basically HTTP 200 means what server correctly processes user request (in case of there is no seats on the plane it is no matter because user request was correctly processed, it can even return just a number of seats available on the plane, so there will be no business logic errors at all or that business logic can be on client side. Business logic error is an abstract meaning, but HTTP error is more definite).

Alexanderius
  • 822
  • 11
  • 27
12

To clarify, you should use HTTP error codes where they fit with the protocol, and not use HTTP status codes to send business logic errors.

Errors like insufficient balance, no cabs available, bad user/password qualify for HTTP status 200 with application specific error handling in the response body.

See this software engineering answer:

I would say it is better to be explicit about the separation of protocols. Let the HTTP server and the web browser do their own thing, and let the app do its own thing. The app needs to be able to make requests, and it needs the responses--and its logic as to how to request, how to interpret the responses, can be more (or less) complex than the HTTP perspective.

Vedant Agarwala
  • 18,146
  • 4
  • 66
  • 89
  • 4
    This might be a matter of opinion but I disagree. These errors exist for a reason, no need to reinvent a way to send standard error, just use the HTTP spec. If the request is malformed, send 400, if the user doesn't have access to the resource, send 403, etc. https://httpstatuses.com/ – Alexandre Testu Nov 19 '19 at 15:23
6

I think people have put too much weight into the application logic versus protocol matter. The important thing is that the response should make sense. What if you have an API that serves a dynamic resource and a request is made for X which is derived from template Y with data Z and either Y or Z isn't currently available? Is that a business logic error or a technical error? The correct answer is, "who cares?"

Your API and your responses need to be intelligible and consistent. It should conform to some kind of spec, and that spec should define what a valid response is. Something that conforms to a valid response should yield a 200 code. Something that does not conform to a valid response should yield a 4xx or 5xx code indicative of why a valid response couldn't be generated.

If your spec's definition of a valid response permits { "error": "invalid ID" }, then it's a successful response. If your spec doesn't make that accommodation, it would be a poor decision to return that response with a 200 code.

I'd draw an analogy to calling a function parseFoo. What happens when you call parseFoo("invalid data")? Does it return an error result (maybe null)? Or does it throw an exception? Many will take a near-religious position on whether one approach or the other is correct, but ultimately it's up to the API specification.

"The status-code element is a three-digit integer code giving the result of the attempt to understand and satisfy the request"

Obviously there's a difference of opinion with regards to whether "successfully returning an error" constitutes an HTTP success or error. I see different people interpreting the same specs different ways. So pick a side, sure, but also accept that either way the whole world isn't going to agree with you. Me? I find myself somewhere in the middle, but I'll offer some commonsense considerations.

  1. If your server-side code catches an unexpected exception when dispatching a request, that sounds like the very definition of a 500 Internal Server Error. This seems to be OP's situation. The application should not return a 200 for unexpected errors, but also see point 3.
  2. If your server-side code should be able to gracefully handle a given invalid input, and it doesn't constitute an "exceptional" error condition, your spec should accommodate HTTP 200 responses that provide meaningful diagnostic information.
  3. Above all: Have a spec. Make it consistent. Stick to it.

In OP's situation, it sounds like you have a de-facto standard that unhandled exceptions yield a 200 with a distinguishable response body. It's not ideal, but if it's not breaking things and actively causing problems, you probably have bigger, more important problems to solve.

snarf
  • 2,684
  • 1
  • 23
  • 26
5

HTTP Is the Protocol handling the transmission of data over the internet.

If that transmission breaks for whatever reason the HTTP error codes tell you why it can't be sent to you.

The data being transmitted is not handled by HTTP Error codes. Only the method of transmission.

HTTP can't say 'Ok, this answer is gobbledigook, but here it is'. it just says 200 OK.

i.e : I've completed my job of getting it to you, the rest is up to you.

I know this has been answered already but I put it in words I can understand. sorry for any repetition.

saAction
  • 2,035
  • 1
  • 13
  • 18
Chris Groves
  • 51
  • 1
  • 1
  • Let me say also that it is up to the programmers and developers to report server-side errors properly and let the user know what kind of problem exists at the server end. e.g sorry this page is broken, or e.g. I'm busy right now updating my database, be with you soon. – Chris Groves Sep 10 '18 at 13:26
0

I am recently working on an ASP.net project which runs on IIS server, and IIS server tend to append default HTMLs in the response if there's anything wrong.

The problem is, the project is an API service that talks with json only, so we wanted to avoid IIS server from doing that. What's worse, OS is in Traditional Chinese so IIS server's default HTMLs are in BIG-5 instead of UTF-8! That confused our frontend developers alot, because response becomes gibberish then.

Sadly I don't have privilege to switch ourselves away from using IIS server too, nor to change the configurations. So in the end, for all the business errors and exceptions we can catch in the backend, we send 200 OK while wrapping actual http status code/message in the response json.

I think that although this is against traditional HTTP codes definition, it avoids unwanted influences towards response between server and client.

I am not a frontend guy so not sure - but I guess this also ceases the need for looking at both HTTP status and body for either a request is successful.

Xiang Wei Huang
  • 336
  • 1
  • 9