Stop flagging JAX-RS/Spring MVC spans as errors when the exception maps to a non-5xx response - #12248
Open
katzj wants to merge 2 commits into
Open
Stop flagging JAX-RS/Spring MVC spans as errors when the exception maps to a non-5xx response#12248katzj wants to merge 2 commits into
katzj wants to merge 2 commits into
Conversation
Author
|
Probably should be labeled with |
katzj
marked this pull request as ready for review
August 20, 2026 19:45
katzj
requested review from
bric3 and
jordan-wong
and removed request for
a team
August 20, 2026 19:45
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40720eabb7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…to a non-5xx response JAX-RS and Spring MVC resource/controller methods commonly signal a non-2xx response by throwing an exception (e.g. NotFoundException, ResponseStatusException, or a custom exception annotated with @ResponseStatus) that the framework's own exception-mapping machinery turns into a normal HTTP response. The tracer previously flagged the resource/controller span as an error unconditionally whenever such an exception was thrown, even when the framework maps it to a routine 4xx (or other non-5xx) status - flooding error tracking with non-actionable "errors" for expected control flow. These exceptions already carry their intended status (WebApplicationException's embedded Response, ResponseStatusException/ErrorResponse, or the @ResponseStatus annotation), so the fix decides the error flag from that status against the same "server error" set used for the root HTTP span, instead of unconditionally erroring. @ResponseStatus's value() and code() attributes are @aliasfor each other, but plain reflection on the annotation proxy doesn't resolve that aliasing - if a caller sets only code(), value() still reports its own default (INTERNAL_SERVER_ERROR) rather than the value mirrored from code(). Both Spring decorators now read code() first (reflectively on the Spring 3.1 classpath, which predates code()'s introduction in 4.2) and fall back to value() only when code() is left at its default.
…TTP status Some applications signal a response status via their own exception hierarchy and a generic exception-handling advice, rather than any of the JAX-RS/Spring conventions already handled (WebApplicationException, ResponseStatusException, ErrorResponse, @ResponseStatus). Those exceptions still get unconditionally flagged as errors even when they map to a routine non-5xx response, since the tracer has no way to know what status they carry. DD_TRACE_RESPONSE_STATUS_EXCEPTIONS / trace.response-status.exceptions lets users declare a list of fully.qualified.ExceptionClass#accessorMethod entries; when a thrown exception (or a subclass of one) matches, the named no-arg accessor is invoked reflectively and its numeric return value is used the same way as the built-in status extraction. This keeps the change fully opt-in and precise - it only ever reflects on classes/methods a user explicitly named, rather than guessing at common accessor names across arbitrary exceptions and risking a genuine error being silently cleared. A misconfigured accessor could return a value outside the valid HTTP status range (e.g. -1 as an unknown-status sentinel). That value would otherwise flow straight into Config#getHttpServerErrorStatuses, a BitSet indexed by status code, which throws on a negative index, aborting normal error handling for the span entirely. The accessor return value is now validated as a plausible HTTP status (100-599) before use, falling back to normal error handling otherwise.
katzj
force-pushed
the
katzj/fix-error-flag-on-mapped-exceptions
branch
from
August 21, 2026 13:59
40720ea to
93e9b3b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Does This Do
WebApplicationException(or asubclass, e.g.
NotFoundException), thejax-rs.request/jakarta-rs.requestspan'serror flag is now decided from the status embedded in the exception's
Response,instead of unconditionally being marked as an error.
@ResponseStatus,ResponseStatusException, and (Spring 6+)ErrorResponse(e.g.NoResourceFoundException) on thespring-web-controllerspan.used for the root HTTP span (
DD_TRACE_HTTP_SERVER_ERROR_STATUSES), so behavior staysconsistent with whatever a user has already configured there.
DD_TRACE_RESPONSE_STATUS_EXCEPTIONS/trace.response-status.exceptionsconfig for exceptions that don't follow any of the above conventions - a comma-separated
list of
fully.qualified.ExceptionClass#accessorMethodentries. When a thrown exception(or a subclass of one) matches, the named no-arg accessor is invoked reflectively and its
numeric return value is used the same way. This is opt-in and precise on purpose: it only
ever reflects on classes/methods a user explicitly named, rather than guessing at common
accessor names across arbitrary exceptions (which risks silently clearing a genuine error).
Motivation
JAX-RS and Spring MVC commonly signal a non-2xx response by throwing an exception that the
framework's own exception-mapping machinery turns into a normal HTTP response (e.g. a 404).
The tracer was flagging the resource/controller span as an error unconditionally whenever
such an exception was thrown, even though the actual HTTP response was a routine non-5xx -
flooding error tracking with non-actionable "errors" for expected control flow. The root
span was never affected by this (it already reflects the real status code correctly), which
is why this showed up as a healthy root span next to an errored child span.
Solves #7141
Solves #7288
Additional Notes
still flagged as errors as before.
DD_TRACE_RESPONSE_STATUS_EXCEPTIONSconfig will need a follow-upupdate in the Datadog docs site.
Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issue