diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91faffd..91551dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ any parts of the framework not mentioned in the documentation should generally b
 
 * Fixed invalid relationship pointer in error objects when field naming formatting is used.
 * Properly resolved related resource type when nested source field is defined.
+* Prevented overwriting of pointer in custom error object
 
 ### Added
 
diff --git a/docs/usage.md b/docs/usage.md
index 939e4e6..952fe80 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -237,7 +237,7 @@ class MyViewset(ModelViewSet):
 
 ```
 
-### Exception handling
+### Error objects / Exception handling
 
 For the `exception_handler` class, if the optional `JSON_API_UNIFORM_EXCEPTIONS` is set to True,
 all exceptions will respond with the JSON:API [error format](https://jsonapi.org/format/#error-objects).
@@ -245,6 +245,21 @@ all exceptions will respond with the JSON:API [error format](https://jsonapi.org
 When `JSON_API_UNIFORM_EXCEPTIONS` is False (the default), non-JSON:API views will respond
 with the normal DRF error format.
 
+In case you need a custom error object you can simply raise an `rest_framework.serializers.ValidationError` like the following:
+
+```python
+raise serializers.ValidationError(
+    {
+        "id": "your-id",
+        "detail": "your detail message",
+        "source": {
+            "pointer": "/data/attributes/your-pointer",
+        }
+
+    }
+)
+```
+
 ### Performance Testing
 
 If you are trying to see if your viewsets are configured properly to optimize performance,
diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py
index 8317c10..2e86e76 100644
--- a/rest_framework_json_api/utils.py
+++ b/rest_framework_json_api/utils.py
@@ -417,21 +417,20 @@ def format_error_object(message, pointer, response):
     if isinstance(message, dict):
 
         # as there is no required field in error object we check that all fields are string
-        # except links and source which might be a dict
+        # except links, source or meta which might be a dict
         is_custom_error = all(
             [
                 isinstance(value, str)
                 for key, value in message.items()
-                if key not in ["links", "source"]
+                if key not in ["links", "source", "meta"]
             ]
         )
 
         if is_custom_error:
             if "source" not in message:
                 message["source"] = {}
-            message["source"] = {
-                "pointer": pointer,
-            }
+            if "pointer" not in message["source"]:
+                message["source"]["pointer"] = pointer
             errors.append(message)
         else:
             for k, v in message.items():

diff --git a/tests/test_utils.py b/tests/test_utils.py
index 9b47e9f..038e8ce 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -7,6 +7,7 @@ from rest_framework.views import APIView
 
 from rest_framework_json_api import serializers
 from rest_framework_json_api.utils import (
+    format_error_object,
     format_field_name,
     format_field_names,
     format_link_segment,
@@ -389,3 +390,45 @@ def test_get_resource_type_from_serializer_without_resource_name_raises_error():
         "can not detect 'resource_name' on serializer "
         "'SerializerWithoutResourceName' in module 'tests.test_utils'"
     )
+
+
+@pytest.mark.parametrize(
+    "message,pointer,response,result",
+    [
+        # Test that pointer does not get overridden in custom error
+        (
+            {
+                "status": "400",
+                "source": {
+                    "pointer": "/data/custom-pointer",
+                },
+                "meta": {"key": "value"},
+            },
+            "/data/default-pointer",
+            Response(status.HTTP_400_BAD_REQUEST),
+            [
+                {
+                    "status": "400",
+                    "source": {"pointer": "/data/custom-pointer"},
+                    "meta": {"key": "value"},
+                }
+            ],
+        ),
+        # Test that pointer gets added to custom error
+        (
+            {
+                "detail": "custom message",
+            },
+            "/data/default-pointer",
+            Response(status.HTTP_400_BAD_REQUEST),
+            [
+                {
+                    "detail": "custom message",
+                    "source": {"pointer": "/data/default-pointer"},
+                }
+            ],
+        ),
+    ],
+)
+def test_format_error_object(message, pointer, response, result):
+    assert result == format_error_object(message, pointer, response)

Avoid overwriting of pointer when using custom errors
The code that produces JSON:API error objects assumes that all fields being validated are under `/data/attributes`:

https://github.com/django-json-api/django-rest-framework-json-api/blob/b0257c065ac2439036ac0543139e7f5913755177/rest_framework_json_api/utils.py#L339

and there doesn't appear to be a way to override the `pointer` value when specifying the field on a serializer.

Use case: I would like to be able to specify a serializer for the top-level `"meta"` field and have any validation errors on that data generate responses properly populated with `"source": {"pointer": "/meta/foo"}`.
tests/test_utils.py::test_format_error_object[message0-/data/default-pointer-response0-result0]
tests/test_utils.py::test_get_related_resource_type_from_nested_source[m2m_source.targets-ManyToManyTarget-related_field_kwargs0] tests/test_utils.py::test_get_related_resource_type_from_nested_source[m2m_target.sources.-ManyToManySource-related_field_kwargs1] tests/test_utils.py::test_get_related_resource_type_from_nested_source[fk_source.target-ForeignKeyTarget-related_field_kwargs2] tests/test_utils.py::test_get_related_resource_type_from_nested_source[fk_target.source-ForeignKeySource-related_field_kwargs3] tests/test_utils.py::test_get_resource_name_no_view tests/test_utils.py::test_get_resource_name_from_view[False-False-APIView] tests/test_utils.py::test_get_resource_name_from_view[False-True-APIViews] tests/test_utils.py::test_get_resource_name_from_view[dasherize-False-api-view] tests/test_utils.py::test_get_resource_name_from_view[dasherize-True-api-views] tests/test_utils.py::test_get_resource_name_from_view_custom_resource_name[False-False] tests/test_utils.py::test_get_resource_name_from_view_custom_resource_name[False-True] tests/test_utils.py::test_get_resource_name_from_view_custom_resource_name[dasherize-False] tests/test_utils.py::test_get_resource_name_from_view_custom_resource_name[dasherize-True] tests/test_utils.py::test_get_resource_name_from_model[False-False-BasicModel] tests/test_utils.py::test_get_resource_name_from_model[False-True-BasicModels] tests/test_utils.py::test_get_resource_name_from_model[dasherize-False-basic-model] tests/test_utils.py::test_get_resource_name_from_model[dasherize-True-basic-models] tests/test_utils.py::test_get_resource_name_from_model_serializer_class[False-False-BasicModel] tests/test_utils.py::test_get_resource_name_from_model_serializer_class[False-True-BasicModels] tests/test_utils.py::test_get_resource_name_from_model_serializer_class[dasherize-False-basic-model] tests/test_utils.py::test_get_resource_name_from_model_serializer_class[dasherize-True-basic-models] tests/test_utils.py::test_get_resource_name_from_model_serializer_class_custom_resource_name[False-False] tests/test_utils.py::test_get_resource_name_from_model_serializer_class_custom_resource_name[False-True] tests/test_utils.py::test_get_resource_name_from_model_serializer_class_custom_resource_name[dasherize-False] tests/test_utils.py::test_get_resource_name_from_model_serializer_class_custom_resource_name[dasherize-True] tests/test_utils.py::test_get_resource_name_from_plain_serializer_class[False-False] tests/test_utils.py::test_get_resource_name_from_plain_serializer_class[False-True] tests/test_utils.py::test_get_resource_name_from_plain_serializer_class[dasherize-False] tests/test_utils.py::test_get_resource_name_from_plain_serializer_class[dasherize-True] tests/test_utils.py::test_get_resource_name_with_errors[400] tests/test_utils.py::test_get_resource_name_with_errors[403] tests/test_utils.py::test_get_resource_name_with_errors[500] tests/test_utils.py::test_format_field_names[False-output0] tests/test_utils.py::test_format_field_names[camelize-output1] tests/test_utils.py::test_format_field_names[capitalize-output2] tests/test_utils.py::test_format_field_names[dasherize-output3] tests/test_utils.py::test_format_field_names[underscore-output4] tests/test_utils.py::test_undo_format_field_names[False-output0] tests/test_utils.py::test_undo_format_field_names[camelize-output1] tests/test_utils.py::test_format_field_name[False-full_name] tests/test_utils.py::test_format_field_name[camelize-fullName] tests/test_utils.py::test_format_field_name[capitalize-FullName] tests/test_utils.py::test_format_field_name[dasherize-full-name] tests/test_utils.py::test_format_field_name[underscore-full_name] tests/test_utils.py::test_undo_format_field_name[False-fullName] tests/test_utils.py::test_undo_format_field_name[camelize-full_name] tests/test_utils.py::test_format_link_segment[False-first_Name] tests/test_utils.py::test_format_link_segment[camelize-firstName] tests/test_utils.py::test_format_link_segment[capitalize-FirstName] tests/test_utils.py::test_format_link_segment[dasherize-first-name] tests/test_utils.py::test_format_link_segment[underscore-first_name] tests/test_utils.py::test_undo_format_link_segment[False-fullName] tests/test_utils.py::test_undo_format_link_segment[camelize-full_name] tests/test_utils.py::test_format_value[False-first_name] tests/test_utils.py::test_format_value[camelize-firstName] tests/test_utils.py::test_format_value[capitalize-FirstName] tests/test_utils.py::test_format_value[dasherize-first-name] tests/test_utils.py::test_format_value[underscore-first_name] tests/test_utils.py::test_format_resource_type[None-None-ResourceType] tests/test_utils.py::test_format_resource_type[camelize-False-resourceType] tests/test_utils.py::test_format_resource_type[camelize-True-resourceTypes] tests/test_utils.py::test_get_related_resource_type[ManyToManySource-targets-ManyToManyTarget] tests/test_utils.py::test_get_related_resource_type[ManyToManyTarget-sources-ManyToManySource] tests/test_utils.py::test_get_related_resource_type[ForeignKeySource-target-ForeignKeyTarget] tests/test_utils.py::test_get_related_resource_type[ForeignKeyTarget-sources-ForeignKeySource] tests/test_utils.py::test_get_related_resource_type_from_plain_serializer_class[related_field_kwargs0-BasicModel] tests/test_utils.py::test_get_related_resource_type_from_plain_serializer_class[related_field_kwargs1-BasicModel] tests/test_utils.py::test_get_related_resource_type_from_plain_serializer_class[related_field_kwargs2-BasicModel] tests/test_utils.py::test_get_resource_type_from_serializer_without_resource_name_raises_error tests/test_utils.py::test_format_error_object[message1-/data/default-pointer-response1-result1]