diff --git a/CHANGELOG.md b/CHANGELOG.md index 964f6b16..0b05600b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ any parts of the framework not mentioned in the documentation should generally b * `ModelSerializer` fields are now returned in the same order than DRF * Avoided that an empty attributes dict is rendered in case serializer does not provide any attribute fields. +* Avoided shadowing of exception when rendering errors (regression since 4.3.0). ### Removed diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index 2e57fbbd..e12080ac 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -381,11 +381,7 @@ def format_drf_errors(response, context, exc): errors.extend(format_error_object(message, "/data", response)) # handle all errors thrown from serializers else: - # Avoid circular deps - from rest_framework import generics - - has_serializer = isinstance(context["view"], generics.GenericAPIView) - if has_serializer: + try: serializer = context["view"].get_serializer() fields = get_serializer_fields(serializer) or dict() relationship_fields = [ @@ -393,6 +389,11 @@ def format_drf_errors(response, context, exc): for name, field in fields.items() if is_relationship_field(field) ] + except Exception: + # ignore potential errors when retrieving serializer + # as it might shadow error which is currently being + # formatted + serializer = None for field, error in response.data.items(): non_field_error = field == api_settings.NON_FIELD_ERRORS_KEY @@ -401,7 +402,7 @@ def format_drf_errors(response, context, exc): if non_field_error: # Serializer error does not refer to a specific field. pointer = "/data" - elif has_serializer: + elif serializer: # pointer can be determined only if there's a serializer. rel = "relationships" if field in relationship_fields else "attributes" pointer = f"/data/{rel}/{field}" diff --git a/tests/test_views.py b/tests/test_views.py index de5d1b7a..acba7e66 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -154,6 +154,17 @@ def test_list_with_include_nested_related_field( "included" ] + @pytest.mark.urls(__name__) + def test_list_with_invalid_include(self, client, foreign_key_source): + url = reverse("foreign-key-source-list") + response = client.get(url, data={"include": "invalid"}) + assert response.status_code == status.HTTP_400_BAD_REQUEST + result = response.json() + assert ( + result["errors"][0]["detail"] + == "This endpoint does not support the include parameter for path invalid" + ) + @pytest.mark.urls(__name__) def test_list_with_default_included_resources(self, client, foreign_key_source): url = reverse("default-included-resources-list")