Repository: django-json-api/django-rest-framework-json-api

Issue:
Validation of include parameter causes unhandled exception
## Description of the Bug Report

When requesting an API endpoint with the `include` query param, specifying an unsupported value results in an uncaught exception and traceback (below). Note: this only seems to happen when querying using the browseable API. When I use [Insomnia](https://insomnia.rest/), I get a 400 response as I'd expect.

Versions:
- Python: 3.6.15
- Django: 3.1.8
- DRF: 3.12.4
- DRF-JA: 3.1.0

<details><summary>Stack trace (browseable API)</summary>
<pre><code>
Traceback (most recent call last):
  File "/opt/python/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/opt/python/django/core/handlers/base.py", line 204, in _get_response
    response = response.render()
  File "/opt/python/django/template/response.py", line 105, in render
    self.content = self.rendered_content
  File "/opt/python/rest_framework/response.py", line 70, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/opt/python/rest_framework/renderers.py", line 724, in render
    context = self.get_context(data, accepted_media_type, renderer_context)
  File "/opt/python/rest_framework/renderers.py", line 655, in get_context
    raw_data_post_form = self.get_raw_data_form(data, view, 'POST', request)
  File "/opt/python/rest_framework/renderers.py", line 554, in get_raw_data_form
    serializer = view.get_serializer()
  File "/opt/python/rest_framework/generics.py", line 110, in get_serializer
    return serializer_class(*args, **kwargs)
  File "/opt/python/rest_framework_json_api/serializers.py", line 113, in __init__
    validate_path(this_serializer_class, included_field_path, included_field_name)
  File "/opt/python/rest_framework_json_api/serializers.py", line 99, in validate_path
    path
</code></pre>
</details>

<details><summary>400 response (Insomnia)</summary>
<pre><code>
{
  "errors": [
    {
      "detail": "This endpoint does not support the include parameter for path foo",
      "status": "400",
      "source": {
        "pointer": "/data"
      },
      "code": "parse_error"
    }
  ],
  "meta": {
    "version": "unversioned"
  }
}
</code></pre>
</details>

## Checklist

- [x] Certain that this is a bug (if unsure or you have a question use [discussions](https://github.com/django-json-api/django-rest-framework-json-api/discussions) instead)
- [ ] Code snippet or unit test added to reproduce bug
  - Should be reproducible in any minimal app with no include serializers configured


Comments:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 964f6b1..0b05600 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 2e57fbb..e12080a 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}"


Test patch:
diff --git a/tests/test_views.py b/tests/test_views.py
index de5d1b7..acba7e6 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -154,6 +154,17 @@ class TestModelViewSet:
             "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")