Skip to content

Commit 863760c

Browse files
committed
default to a generic error message for unhandled exceptions to avoid unintentionally leaking sensitive data.
fixes #99
1 parent 81246cc commit 863760c

File tree

4 files changed

+54
-3
lines changed

4 files changed

+54
-3
lines changed

docs/changelog.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010
- add support for django 5.2
1111
- add support for DRF 3.16
1212

13+
### Changed (backward-incompatible)
14+
- Unhandled exceptions now return a generic error message by default. This avoids unintentionally leaking
15+
sensitive data included in the exception message. To revert to the old behavior or change the default error
16+
message:
17+
- create a custom exception handler class
18+
```python
19+
from rest_framework.exceptions import APIException
20+
from drf_standardized_errors.handler import ExceptionHandler
21+
22+
class MyExceptionHandler(ExceptionHandler):
23+
def convert_unhandled_exceptions(self, exc: Exception) -> APIException:
24+
if not isinstance(exc, APIException):
25+
# `return APIException(detail=str(exc))` restores the old behavior
26+
return APIException(detail="New error message")
27+
else:
28+
return exc
29+
```
30+
- Then, update the settings to point to your exception handler class
31+
```python
32+
DRF_STANDARDIZED_ERRORS = {
33+
# ...
34+
"EXCEPTION_HANDLER_CLASS": "path.to.MyExceptionHandler"
35+
}
36+
```
37+
1338
## [0.14.1] - 2024-08-10
1439
### Added
1540
- declare support for django 5.1

docs/faq.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,26 @@ You can check this [issue](https://github.com/ghazi-git/drf-standardized-errors/
4343
for a possible solution. Still, `djangorestframework-camel-case` is built to work specifically with
4444
the default exception handler from DRF. It assumes that field names are the keys in the returned dict.
4545
So, that does not work well with this package.
46+
47+
48+
## How can I change the default error message for unhandled exceptions
49+
50+
You need to create a custom exception handler class
51+
```python
52+
from rest_framework.exceptions import APIException
53+
from drf_standardized_errors.handler import ExceptionHandler
54+
55+
class MyExceptionHandler(ExceptionHandler):
56+
def convert_unhandled_exceptions(self, exc: Exception) -> APIException:
57+
if not isinstance(exc, APIException):
58+
return APIException(detail="New error message")
59+
else:
60+
return exc
61+
```
62+
Then, update the settings to point to your exception handler class
63+
```python
64+
DRF_STANDARDIZED_ERRORS = {
65+
# ...
66+
"EXCEPTION_HANDLER_CLASS": "path.to.MyExceptionHandler"
67+
}
68+
```

drf_standardized_errors/handler.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ def convert_unhandled_exceptions(self, exc: Exception) -> exceptions.APIExceptio
7575
has a 500 status code.
7676
"""
7777
if not isinstance(exc, exceptions.APIException):
78-
return exceptions.APIException(detail=str(exc))
78+
# return a generic error message to avoid potentially leaking sensitive
79+
# data and match DRF/django behavior (same generic error message returned
80+
# by django.views.defaults.server_error)
81+
return exceptions.APIException(detail="Server Error (500)")
7982
else:
8083
return exc
8184

tests/test_settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def test_custom_exception_formatter_class(settings, api_client):
4141
assert response.status_code == 500
4242
assert response.data["type"] == "server_error"
4343
assert response.data["code"] == "error"
44-
assert response.data["message"] == "Internal server error."
44+
assert response.data["message"] == "Server Error (500)"
4545
assert response.data["field_name"] is None
4646

4747

@@ -82,7 +82,7 @@ def test_enable_in_debug_for_unhandled_exception_is_true(
8282
assert len(response.data["errors"]) == 1
8383
error = response.data["errors"][0]
8484
assert error["code"] == "error"
85-
assert error["detail"] == "Internal server error."
85+
assert error["detail"] == "Server Error (500)"
8686
assert error["attr"] is None
8787

8888

0 commit comments

Comments
 (0)