Skip to content

Fix DDSpan.addThrowable crashing when exception getMessage() throws#11428

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
masterfrom
vzakharov/fix-addthrowable-broken-getmessage
May 21, 2026
Merged

Fix DDSpan.addThrowable crashing when exception getMessage() throws#11428
gh-worker-dd-mergequeue-cf854d[bot] merged 4 commits into
masterfrom
vzakharov/fix-addthrowable-broken-getmessage

Conversation

@ValentinZakharov
Copy link
Copy Markdown
Contributor

What Does This Do

Adds StackTraces.safeGetMessage(Throwable) and uses it in DDSpan.addThrowable where getMessage() was called directly. Also guards StackTraces.getStackTrace() which calls getMessage() indirectly via printStackTrace()toString().

# Motivation
A third-party exception's getMessage() can throw if it internally uses MessageFormat.format() with non-integer placeholders (e.g. {TotalMilliseconds}). MessageFormat tries to parse the placeholder as an argument index via Integer.parseInt, which throws NumberFormatExceptionIllegalArgumentException

Before the fix:
image

After the fix:
image

Additional Notes

  • safeGetMessage uses catch (Exception e) intentionally - Error subtypes (OutOfMemoryError, StackOverflowError) are not caught as masking them would cause more harm than good.
  • When printStackTrace() fails, the fallback captures frames of the top-level exception via getStackTrace()[]. The Caused by: chain is lost in this edge case - acceptable given how rarely getMessage() throws.
  • ERROR_TYPE and ERROR_MSG (fallback string) are always recorded, giving enough signal to identify the problem even without a full stack trace.

Contributor Checklist

Jira ticket: [PROJ-IDENT]

Note: Once your PR is ready to merge, add it to the merge queue by commenting /merge. /merge -c cancels the queue request. /merge -f --reason "reason" skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.

@ValentinZakharov ValentinZakharov self-assigned this May 20, 2026
@ValentinZakharov ValentinZakharov requested a review from a team as a code owner May 20, 2026 11:13
@ValentinZakharov ValentinZakharov added type: bug Bug report and fix comp: core Tracer core labels May 20, 2026
@datadog-prod-us1-5

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@amarziali amarziali left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks ok. I left some comments - You might need to run spotless to fix the formatting

Comment on lines +18 to +24
* Safely retrieves the message from a throwable. Returns {@code null} if {@code t} is {@code
* null}, or a diagnostic string of the form {@code "(Exception message unavailable for ClassName:
* getMessage() threw ExceptionType)"} if {@link Throwable#getMessage()} itself throws.
* Third-party exception classes occasionally use formatting utilities (e.g. {@code
* java.text.MessageFormat}) inside {@code getMessage()}, which can throw when the pattern
* contains non-integer placeholders.
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be formatted as a standard javadoc. i.e.

@param ...
@return ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks

String cutMessage = "\t... trace centre-cut to " + maxChars + " chars ...";
int retainedLength = maxChars - cutMessage.length() - 2; // 2 for the newlines
if (retainedLength <= 0) {
return cutMessage + System.lineSeparator();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks added so will modify also the existing implementation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the fix for edge case: when maxChars is smaller than cutMessage itself, retainedLength goes negative and substring() throws. Caught it while working in this area

Comment on lines +50 to +54
t.getClass().getName()
+ System.lineSeparator()
+ Arrays.stream(t.getStackTrace())
.map(f -> "\tat " + f)
.collect(Collectors.joining(System.lineSeparator()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For precision the original implementation also prints the stack for suppressed and cause. I think that, for simplicity, this will be ok.

} catch (Exception ignored) {
// printStackTrace() failed (e.g. getMessage() throws inside toString()).
// Reconstruct from getStackTrace() so the call site is still locatable.
trace =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not know if getStackTrace can also throw in some cases? I would also protect inside a try catch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Fixed! Thanks

@ValentinZakharov ValentinZakharov added this pull request to the merge queue May 21, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 21, 2026
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented May 21, 2026

/merge

@gh-worker-devflow-routing-ef8351
Copy link
Copy Markdown

gh-worker-devflow-routing-ef8351 Bot commented May 21, 2026

View all feedbacks in Devflow UI.

2026-05-21 14:39:23 UTC ℹ️ Start processing command /merge


2026-05-21 14:39:29 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 1h (p90).


2026-05-21 15:54:41 UTC ℹ️ MergeQueue: This merge request was merged

@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot merged commit 775b570 into master May 21, 2026
570 checks passed
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot deleted the vzakharov/fix-addthrowable-broken-getmessage branch May 21, 2026 15:54
@github-actions github-actions Bot added this to the 1.63.0 milestone May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core type: bug Bug report and fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants