DRF validation errors: alert as client errors or system errors in Sentry, Prometheus, Datadog?
0 reputation · 06 Feb 2021, 20:49 UTC
0 reputation · 06 Feb 2021, 20:49 UTC
Django REST Framework emits structured exceptions and logs that monitoring backends—Sentry, Prometheus, Datadog—ingest for alerting. The integration point is DRF's DEFAULT_EXCEPTION_HANDLER and custom throttle classes, which enrich or convert validation failures (serializer.is_valid() returning False) into events or metrics before they reach the observability stack.
Validation errors sit at a semantic boundary: they represent rejected client input (400 responses) but may also indicate upstream data-integrity risks, schema drift, or buggy client integrations. Sentry's Django integration captures unhandled DRF exceptions as errors, yet 4xx responses are recorded as level:warning events by default. Prometheus histograms (django_http_requests_latency_seconds_by_view) and custom throttle counters (django_throttle_rejections_total) treat validation failures as successful request completions with non-2xx status codes. Datadog APM tags traces with http.status_code:400 but does not distinguish validation from other client errors.
Teams split on whether to route validation failures to paging alerts (system error) or to dashboards only (client error). The decision affects SENTRY_IGNORE_EXCEPTIONS filters, Prometheus alerting rules on http_status=400 rates, and Datadog monitor thresholds.
before_send, Prometheus recording rules, and Datadog APM tagging without duplicating logic in every view?34275 reputation · 07 Feb 2021, 02:47 UTC
Treat DRF validation failures as client errors by default. Page only when they deviate from an established baseline or come from trusted/internal sources, which suggests schema drift, an upstream dependency problem, abusive integration, or a bug in your own API. Otherwise increment a dashboard counter and do not page.
DRF's default exception handler converts ValidationError into a 400 response; serializer.is_valid() raises only when called with raise_exception=True. A handled 400 is not an unhandled exception, so Sentry may not see it unless your custom handler explicitly captures it. Sentry event level, Prometheus label names, and Datadog tag behavior depend on your SDK/agent versions; verify them in your environment.
| Route | Condition |
|---|---|
| Dashboard only | Sporadic 400s from public clients, expected malformed input, rate within baseline, low-impact endpoint. |
| Page or alert route | Sudden rate change per endpoint/client/schema version, 400s from trusted/internal clients, repeated same validation failure from one client, high-value endpoint, or errors coinciding with upstream dependency failures. |
ValidationError and set request.drf_validation_classification to client_error or system_error.system_error validation failures to Sentry with level: error and tags http_status_code=400, drf_validation_error=true, drf_validation_classification=system_error. Keep client_error out of Sentry or as a non-paging warning; enforce this in before_send so the rule is not repeated per view.drf_validation_errors_total{view,status,error_code,classification,client} from the same handler or middleware. Alert on rate deviation from baseline, not on every 400. Keep throttle rejections in a separate counter.drf.validation_error=true, drf.validation.classification, and http.status_code=400. Monitor the validation tag rate, not all http.status_code:400 traces.is_valid() and is_valid(raise_exception=True); confirm whether a 400 response is returned or an exception is raised.before_send applied the intended level and tags.Missing diagnostic detail: how are validation failures currently surfaced—returned 400 responses or raised exceptions—and do they reach Sentry? This changes whether you need a custom handler to capture them at all.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.