Which status code should I use for failed validations or invalid duplicates?
Asked Answered
F

10

1048

I am building an application with a REST-based API and have come to the point where I am specifying status codes for each requests.

What status code should i send for requests failing validation or where a request is trying to add a duplicate in my database?

I've looked through http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html but none of them seems right.

Is there a common practice when sending status codes?

Farce answered 20/7, 2010 at 13:3 Comment(4)
See: #1960447Hypoploid
Open httpstatus.es, Right Click >> Pin Tab :PCad
Possible duplicate of What's an appropriate HTTP status code to return by a REST API service for a validation failure?Should
For duplicate see HTTP response code for POST when resource already existsEulaheulalee
H
997

For input validation failure: 400 Bad Request + your optional description. This is suggested in the book "RESTful Web Services". For double submit: 409 Conflict


Update June 2014

The relevant specification used to be RFC2616, which gave the use of 400 (Bad Request) rather narrowly as

The request could not be understood by the server due to malformed syntax

So it might have been argued that it was inappropriate for semantic errors. But not any more; since June 2014 the relevant standard RFC 7231, which supersedes the previous RFC2616, gives the use of 400 (Bad Request) more broadly as

the server cannot or will not process the request due to something that is perceived to be a client error

Hypoploid answered 20/7, 2010 at 13:5 Comment(10)
Yes, the request body is part of the syntax.Hypoploid
Yeah, 400 Bad Request seems to be the closest option.Farce
I will go with 400 Bad Request and 409 Conflict until i find something that fits better.Farce
Bad request is definitely the most common response to this kind of issue. The only other alternative is 422 Unprocessable Entity. It actually comes from WebDav but it is perfectly valid to reuse any status code that has been registered with IANA.Damaraland
So how do you differentiate between malformed data that the server can't even parse, and a validation error? A client would handle these two responses completely differently. For validation, they'd likely display the errors to the user. For truly "malformed data", they would log the error so the the bug in the method that generates the request could be fixed.Fancie
I disagree with your interpretation of RFC7231, although it states something perceived to be a client error, all the examples given in this paragraph are violations of HTTP protocol, not logical errors: syntax, framing, routing. Thus, I consider that HTTP spec does not allow 400 for failed validation on application level.Binnings
why not use a 422 - Unprocessable entity? Seems more logical to meEmblazon
I agree that 409 is appropriate for dupes, but sometimes dupes are a side effects of an error case. For example, a mobile client may timeout during submission and never receive 201 Created with a payload containing an ID that they need. I submit that when appropriate (or even possible), an alternative would be a 303, redirecting to the original that was created before the timeout.Fasano
I have read that custom status text is deprecated in HTTP/2, can't find the reference unfortunately.Shoifet
The update is out of date. RFC-9110 supercedes RFC-7231. RFC-9110 states that 422 - Unprocessable Entity is used when the server understands the content type, and and the requested content is correct, but it was unable to process the contained instructions. 422 was missing in RFC-7231, and now seems to clearly define a case when a validation fails (i.e. a number is out of an expected range) and so the server cannot continue to process the contained instructions.Excide
R
300

I recommend status code 422, "Unprocessable Entity".

11.2. 422 Unprocessable Entity

The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

Ralina answered 20/7, 2010 at 14:56 Comment(13)
Of course it is an HTTP status code, see iana.org/assignments/http-status-codes. There are more status codes than those defined in RFC 2616.Ralina
@deamon: Speaking of non-codes, the Wikipedia page you linked to (somewhere in this question), notes several sub-statuses (which are not even syntactically valid HTTP status codes - "The Status-Code element is a 3-digit integer result code") invented by the IIS server team ("403.4 - SSL required"). Trying to eat your cake and have it, too?Verso
WebDAV is a HTTP extension. "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" So, status code 422 is not a http status code, but a status code of an extions of http.Hypoploid
deamon, that doesn't make sense. HTTP defines how to define new codes, and that's what WebDAV is doing. There's a status code registry for a reason.Ralina
Piskvor, that's actually questionable :-). It probably wouldn't happen under the registration procedure defined in the current draft.Ralina
Piskvor, Oh, it's NOT in. Good. :-)Ralina
This is what Twitter uses now. Not saying they're the law, but worth noting.Fancie
FYI - RFC description of 422: 11.2. 422 Unprocessable Entity The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.Eckstein
d'oh! I didn't realize I was adding to a nearly 3 year old comment. Sorry.Eckstein
@TurtlePowered: I see no problem with that - some of the discussions in the comments have been going on for years, literally.Verso
And threads don't 'expire'. They need to be kept living or top google search results start to become inaccurate.Juristic
I want the code and now I have it. I can't see a problem.Reconciliatory
IMO 422 is better than 400 or 403 because 422 can only be interpreted to mean one thing - the request body is well formed but invalid in some way. Where as 400 and 403 have other meanings (400 the request body is not well formed and 403 a user is authenticated but is not allowed to access a resource).Wheelsman
V
299
  • Failed validation: 403 Forbidden ("The server understood the request, but is refusing to fulfill it"). Contrary to popular opinion, RFC2616 doesn't say "403 is only intended for failed authentication", but "403: I know what you want, but I won't do that". That condition may or may not be due to authentication.
  • Trying to add a duplicate: 409 Conflict ("The request could not be completed due to a conflict with the current state of the resource.")

You should definitely give a more detailed explanation in the response headers and/or body (e.g. with a custom header - X-Status-Reason: Validation failed).

Verso answered 20/7, 2010 at 13:24 Comment(19)
@deamon: That is not the specification, that's Wikipedia, i.e. someone's opinion on "what HTTP status codes mean"; note that the page essentialy says "this is what Apache means with 403, this is what IIS means with 403", and nowhere does it reference the official RFC. You seem to be repeating "403 means whatever Apache says". NOT. The actual RFC (which is the relevant document, not Apache's implementation, not IIS' implementation, not anyone else's implementation) is here: w3.org/Protocols/rfc2616/rfc2616-sec10.htmlVerso
I know this specification. The emphasis is on "forbidden" what means "access denied in any case".Hypoploid
"10.4.4 403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead." I see no emphasis there ("SHOULD/SHOULD NOT" are RFC 2119 keywords, not emphasis); that's your idea what "forbidden" means, not RFC's.Verso
I like this answer, but still see one small problem. According to the spec, when a 403 is returned, "the request SHOULD NOT be repeated". However, returning a 409 "is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request". In the case of a duplicate, I think 403 is then more appropriate, as you cannot really resolve the conflict (except by deleting the previous instance of the resource).Mushroom
This is a good answer. I agree with Piskvor that an invalid payload isn't the same thing as a syntax error with the request.Kalb
For the error message itself you should modify the reason phrase, so sending the header HTTP/1.0 403 Form validation errors is the cleanest way to go.Bimbo
Having read the rfc this seems like the closest match in meaning for validation errors.Lallans
IMO, 422 "Unprocessable Entity" makes much more sense. My reasoning is that it's not that the server refuses to fulfill request, it's that the server can't fulfill the request.Choleric
That might be an option, yes. I was trying to stay strictly within RFC2616 here - see the emotions that have flared up when @Julian Reschke has brought up 422 in a sibling answer: https://mcmap.net/q/53138/-which-status-code-should-i-use-for-failed-validations-or-invalid-duplicatesVerso
@Piskvor, as the X- prefix in custom HTTP headers is deprecated you could change your example to just Status-Reason: Validation failed.Durman
@roberkules: Deprecated? [citation-needed]Verso
@Piskvor, sure: tools.ietf.org/html/rfc6648 See also https://mcmap.net/q/18578/-custom-http-headers-naming-conventionsDurman
@roberkules: Interesting, thanks. I'll stick to Makes no recommendation as to whether existing "X-" parameters ought to remain in use or be migrated to a format without the "X-"; this is a matter for the creators or maintainers of those parameters. and keep it here as-is.Verso
-1: 403 Forbidden implies the request was comprehensible; usually invalid input means an incomprehensible requestZwart
From RFC 7231: “The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.” tools.ietf.org/html/rfc7231#section-6.5.3Berryman
@PatrickOscity: See publication date and authors. I think that this SO question has influenced the wording of the section you are linking to ;)Verso
downvoted answer because it's no longer valid due to newer 2014 rfc7231, previous answer with 400/409 seems most accurateBottom
I up-voted this answer cause 403 is more indicative. If I have a 403 and there is no descriptive error message, at least I have a clue. 404 overlaps conditions and I would then require dot dig.Hazan
The 403 is "Forbidden" specifically the "user" attempting that action is not allowed. It is an Authorization failure. It means I know who you are, but you don't have the permission to do that. I don't think it applies here. Here we are talking about the content and not the user. The appropriate status, in my opinion, would be 422. That indicates, your message was well formed, I can read it, but you're asking me to do things not that are not allowed. An example might be sending a property value that is not in the list of allowed enumerations.Bedaub
M
99

200,300, 400, 500 are all very generic. If you want generic, 400 is OK.

422 is used by an increasing number of APIs, and is even used by Rails out of the box.

No matter which status code you pick for your API, someone will disagree. But I prefer 422 because I think of '400 + text status' as too generic. Also, you aren't taking advantage of a JSON-ready parser; in contrast, a 422 with a JSON response is very explicit, and a great deal of error information can be conveyed.

Speaking of JSON response, I tend to standardize on the Rails error response for this case, which is:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

This format is perfect for form validation, which I consider the most complex case to support in terms of 'error reporting richness'. If your error structure is this, it will likely handle all your error reporting needs.

Muslim answered 4/4, 2013 at 17:40 Comment(3)
What about errors arising from interactions among the args. That is, arg1 is valid and arg2 is valid, but the combination of the two, with the the specific values sent, is not valid.Brabant
I wouldn't over think it; just pick one that appears to own the relationship.Muslim
or even just error on both args. As a user, I think I'd want to see the error on each of the fields that are conflicting, I think.Volsci
P
94

A duplicate in the database should be a 409 CONFLICT.

I recommend using 422 UNPROCESSABLE ENTITY for validation errors.

I give a longer explanation of 4xx codes here.

Predella answered 16/10, 2014 at 23:5 Comment(0)
O
81

200

Ugh... (309, 400, 403, 409, 415, 422)... a lot of answers trying to guess, argue and standardize what is the best return code for a successful HTTP request but a failed REST call.

It is wrong to mix HTTP status codes and REST status codes.

However, I saw many implementations mixing them, and many developers may not agree with me.

HTTP return codes are related to the HTTP Request itself. A REST call is done using a Hypertext Transfer Protocol request and it works at a lower level than invoked REST method itself. REST is a concept/approach, and its output is a business/logical result, while HTTP result code is a transport one.

For example, returning "404 Not found" when you call /users/ is confuse, because it may mean:

  • URI is wrong (HTTP)
  • No users are found (REST)

"403 Forbidden/Access Denied" may mean:

  • Special permission needed. Browsers can handle it by asking the user/password. (HTTP)
  • Wrong access permissions configured on the server. (HTTP)
  • You need to be authenticated (REST)

And the list may continue with '500 Server error" (an Apache/Nginx HTTP thrown error or a business constraint error in REST) or other HTTP errors etc...

From the code, it's hard to understand what was the failure reason, a HTTP (transport) failure or a REST (logical) failure.

If the HTTP request physically was performed successfully it should always return 200 code, regardless is the record(s) found or not. Because URI resource is found and was handled by the HTTP server. Yes, it may return an empty set. Is it possible to receive an empty web-page with 200 as HTTP result, right?

Instead of this you may return 200 HTTP code with some options:

  • "error" object in JSON result if something goes wrong
  • Empty JSON array/object if no record found
  • A bool result/success flag in combination with previous options for a better handling.

Also, some internet providers may intercept your requests and return you a 404 HTTP code. This does not means that your data are not found, but it's something wrong at transport level.

From Wiki:

In July 2004, the UK telecom provider BT Group deployed the Cleanfeed content blocking system, which returns a 404 error to any request for content identified as potentially illegal by the Internet Watch Foundation. Other ISPs return a HTTP 403 "forbidden" error in the same circumstances. The practice of employing fake 404 errors as a means to conceal censorship has also been reported in Thailand and Tunisia. In Tunisia, where censorship was severe before the 2011 revolution, people became aware of the nature of the fake 404 errors and created an imaginary character named "Ammar 404" who represents "the invisible censor".

Why not simply answer with something like this?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

Google always returns 200 as status code in their Geocoding API, even if the request logically fails: https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook always return 200 for successful HTTP requests, even if REST request fails: https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

It's simple, HTTP status codes are for HTTP requests. REST API is Your, define Your status codes.

Ophir answered 23/9, 2017 at 12:42 Comment(17)
Actually, using HTTP status codes for REST is even more confusing down the road: 1) you see 4xx in your developer's toolbox and you can't say by just glancing at it whether server returned some sensible value or failed to process your request at all and then 2) all your error/exception/catch handlers should check what server returned as a response (mostly they don't since you'd have to do it on every service call) and many times 3) you get the same payload (type) on both success and error path leading to complicated/duplicated code... Very confusing indeed.Bald
This answer confuses the original semantics of the HTTP protocol vs how REST over HTTP as an architectural style re-purposes HTTP to implement web service APIs. As an architectural style, REST is not a standard to be rigorously followed, it is a suggested approach. Using a 200 response for a validation failure is not right or wrong, however it is confusing to your clients to respond that the request succeeded, but actually failed due to a validation failure, an important detail that is obscured within the body of the response, the semantics of which the client has to parse to understand.Hate
@KevinHooke, this answer argue why using HTTP return codes is a bad idea for REST status calls.Ophir
@Ophir if your API call fails but you return 200 indicating success, how is this a good idea? it's unclear and confusing to consumers of your API.Hate
Correct for many reasons, not just the separation of HTTP vs REST errors. REST validation often requires more nuance. For example, record accepted but flagged as a duplicate vs. rejected for a unique index violation. You also want a consistent return model. The .NET BadRequest() method has its own return model that will differ from your regular return model. That's a nightmare to parse. @KevinHooke, returning HTTP 200 for a REST validation error is like saying, "I received your message, the answer is no, and here's why." Returning HTTP 400 says, "I don't know what you're talking about."Edieedification
the "because google does it , it must be right" argument is crazy to me..its ok to challenge something google has implemented kids. Returning HTTP 200 for an unsuccessful rest call confuses the caller of the API it should be 4xx and one can include a pretty JSON/XML in the body...lets stop the insanity together.Ananna
@JerylCook, last phase with Google I added after one year of original answer, when found accidentally how does Google, during one integration. And I thought: Hey Google read this answer, they think I am right and they copied me. I should ask for royalties. :) I think I argued enough about caller confusion... Http status codes are for Http requests. Rest codes: define yourself. Http codes will not be enough for a complex API design. Lets eat the soup with a spoon, not with a fork.Ophir
Oh h..t, just checked how Facebook do it, crazy... they too copied me ) developers.facebook.com/docs/graph-api/using-graph-api/…Ophir
What would you say if some of Google projects resources returns 2xx but others 4xx? Did you checked all of them? Google is quite large and they fail quite often. They have a lot of nice stuff too. So when you mention some company it is not an argument, but rather an illustration. The idea you proposed is new for me, and have some sense, but as REST is not a standard how to compare it with HTTP?Millett
The explanation makes a lot of sense to me and I will implement it like so. But I will rename the "result" property to "success" because "result=false" is confusing and not telling me anything. There is a result, but it wasn't successful for some reason is more appropriate.Kef
@BernoulliIT, indeed, many implementations uses "success" property. We also did it in a lot of projects, as front-end like ExtJS impose it.Ophir
Using the HTTP response codes in REST is part of "level 2" of the Richardson maturity model. see (for example) martinfowler.com/articles/richardsonMaturityModel.html#level2: "The important part of this response is the use of an HTTP response code to indicate something has gone wrong". REST does often require more nuance, but the HTTP verbs and status codes do exist, and are worth using as correctly as possible.Pancreatotomy
This answer is plain wrong and indicates misunderstanding of REST, HTTP, and their relationship. REST doesn't define status codes at all, so you can't mix them with HTTP status codes. Response status codes' semantics is defined by the HTTP standard, and these status codes exist in the context of the HTTP interface, not REST. Though, REST style has influenced the design and development of the HTTP. See Roy Fielding's dissertation, specifically chapter 6.Lectionary
@wombatonfire, who said that REST define status codes and should be mixed with HTTP? I agree with you that they should not be mixed, as this answer argues. Did you read it carefully? I see Roy in his paper, especially in 6.3.1.2 are in line with us.Ophir
@Ophir I am not sure what you agree with in my comment, it seems you misunderstood it. What the comment says is that there is NO such thing as REST status codes. The whole answer is based on an imaginary construct. It argues about a non-existent thing, based on a false understanding of REST and its relationship with HTTP.Lectionary
@wombatonfire, a REST result like {"success": false, "code": 123, "text": "Something wrong"} IS a REST status code. Up to you how you define them. Just do not mix it with HTTP status codes, as this answer argues.Ophir
Nice answer. The link on the Google Geocoding API status codes should be updated though: developers.google.com/maps/documentation/geocoding/…Proserpina
S
11

Ember-Data's ActiveRecord adapter expects 422 UNPROCESSABLE ENTITY to be returned from server. So, if you're client is written in Ember.js you should use 422. Only then DS.Errors will be populated with returned errors. You can of course change 422 to any other code in your adapter.

Spermatozoid answered 3/12, 2014 at 22:17 Comment(0)
B
5

Status Code 304 Not Modified would also make an acceptable response to a duplicate request. This is similar to processing a header of If-None-Match using an entity tag.

In my opinion, @Piskvor's answer is the more obvious choice to what I perceive is the intent of the original question, but I have an alternative that is also relevant.

If you want to treat a duplicate request as a warning or notification rather than as an error, a response status code of 304 Not Modified and Content-Location header identifying the existing resource would be just as valid. When the intent is merely to ensure that a resource exists, a duplicate request would not be an error but a confirmation. The request is not wrong, but is simply redundant, and the client can refer to the existing resource.

In other words, the request is good, but since the resource already exists, the server does not need to perform any further processing.

Borax answered 17/3, 2014 at 19:14 Comment(4)
It was my understanding that 304 is intended for GET operations to assist with caching.Fasano
@Fasano That's fair, but 304 also assists with caching. Your comment in a different answer about using 303 would itself have made an excellent answer.Borax
This doesn't make any sense. How are you going to treat a duplicate request as NOT an error? You are adding a NEW resource and you get a "found a duplicate" response. What's next? You don't add it? Then it's a failure, because the INTENTION was to ADD a resource. If you intend to modify the existing resource you do it directly on that existing resource, not by trying to add a new one. If you want to check whether resource exists, you do it by querying the resource, not by attempting to add a new resource and checking if you get back "duplicate warning".Lectionary
In robust distributed systems with retry mechanisms, idempotency is helpful even for resource creation.Flow
E
2

I came to the conclusion to try to follow this rule: If it indicates the client developer error, go with 400 (Bad Request). Otherwise, supposing no client validation at all, if a dumb user is entering invalid data, then use 422 (Unprocessable Entity). If in doubt, prefer 422, or maybe use the one with easier implementation.

This helps the developer to know who actually made the mistake, whether himself or the user.

By a dumb user, I mean non-technical user. An attacker shouldn't matter here: If you were that worried about, you wouldn't use HTTP status codes in the first place. :)

For example, if you're validating a JSON request body against a JSON Schema, 400 is the proper choice (e.g. missing keys, keyword mismatches). However, if you're expecting user to enter a valid email, then you should use 422 (let me say again, suppose there is no client validation).

This can also be helpful in better branching logics. For instance, in the context of a REST API, suppose you have a survey response endpoint, with possible methods of POST and PATCH. In this case, if a client sends an invalid POST request, you might want to send the URI of the new resource back in the Location header for when the status code is 422, but not for 400.

Real world examples are more complicated for sure, but this should work great IMHO.

Earley answered 18/8, 2022 at 13:20 Comment(0)
T
0

I think everyone will have different opinion on this because we all have referred to status codes in various contexts. But what is important is whatever is most widely accepted and known. 400 is known and accepted as validation error response and 409 as name suggests is a conflict. If we say 400 is not right for validation error because server has understood the request, then think of someone asking you a question which you do understand from words but you could have responded and said "oh that is an invalid question" or "that does not make sense" so just because you understood the words does not mean it makes sense. Otherwise we can keep talking about this all day

Theorem answered 31/10, 2023 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.