Error Response Format
The default error response format looks like this
{
"type": "validation_error",
"errors": [
{
"code": "required",
"detail": "This field is required.",
"attr": "name"
}
]
}
type
: can bevalidation_error
,client_error
orserver_error
code
: short string describing the error. Can be used by API consumers to customize their behavior.detail
: User-friendly text describing the error.attr
: set only when the error type is avalidation_error
and maps to the serializer field name orsettings.NON_FIELD_ERRORS_KEY
.
Error Types
Validation Errors
These are ones caused by raising a rest_framework.exceptions.ValidationError
. They are the only error type
that can have more than 1 error. The list of corresponding error codes depends on the serializer and its fields.
Client Errors
Covers all 4xx errors other than validation errors. Here’s a reference to all possible error codes and corresponding exceptions:
Error Code |
Status Code |
DRF Exception |
---|---|---|
parse_error |
400 |
|
authentication_failed |
401 |
|
not_authenticated |
401 |
|
permission_denied |
403 |
|
not_found |
404 |
|
method_not_allowed |
405 |
|
not_acceptable |
406 |
|
unsupported_media_type |
415 |
|
throttled |
429 |
Server Errors
These are ones caused by raising a rest_framework.exceptions.APIException
or by unhandled exceptions.
The corresponding error code is error
and the status code is 500.
Multiple Errors Support
Out of the box, only validation errors would result in an error response with multiple errors. The errors can be for the same field or for different fields. So, a sample DRF error dict like this:
{
"phone": [
ErrorDetail("The phone number entered is not valid.", code="invalid_phone_number")
],
"password": [
ErrorDetail("This password is too short.", code="password_too_short"),
ErrorDetail("The password is too similar to the username.", code="password_too_similar"),
],
}
would be converted to:
{
"type": "validation_error",
"errors": [
{
"code": "invalid_phone_number",
"detail": "The phone number entered is not valid.",
"attr": "phone"
},
{
"code": "password_too_short",
"detail": "This password is too short.",
"attr": "password"
},
{
"code": "password_too_similar",
"detail": "The password is too similar to the username.",
"attr": "password"
}
]
}
Nested Serializers Support
Taking this example
{
"shipping_address": {
"non_field_errors": [ErrorDetail("We do not support shipping to the provided address.", code="unsupported")]
}
}
It will be converted to:
{
"code": "unsupported",
"detail": "We do not support shipping to the provided address.",
"attr": "shipping_address.non_field_errors"
}
Note how the attr
is the combined value of parent serializer field name and nested one. They are separated by
a .
by default, but that can be changed through the setting NESTED_FIELD_SEPARATOR
.
List Serializers Support
This example
{
"recipients": [
{"name": [ErrorDetail("This field is required.", code="required")]},
{"email": [ErrorDetail("Enter a valid email address.", code="invalid")]},
]
}
would be converted to
{
"type": "validation_error",
"errors": [
{
"code": "required",
"detail": "This field is required.",
"attr": "recipients.0.name"
},
{
"code": "invalid",
"detail": "Enter a valid email address.",
"attr": "recipients.1.email"
}
]
}
Note that distinguishing between errors in different objects in the nested list serializer is done using 0-based indexing.