Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,26 @@ public SentryProducerInterceptor(final @NotNull IScopes scopes) {
return record;
}

final @NotNull SpanOptions spanOptions = new SpanOptions();
spanOptions.setOrigin(TRACE_ORIGIN);
final @NotNull ISpan span = activeSpan.startChild("queue.publish", record.topic(), spanOptions);
if (span.isNoOp()) {
return record;
}
try {
final @NotNull SpanOptions spanOptions = new SpanOptions();
spanOptions.setOrigin(TRACE_ORIGIN);
final @NotNull ISpan span =
activeSpan.startChild("queue.publish", record.topic(), spanOptions);
if (span.isNoOp()) {
return record;
}

span.setData(SpanDataConvention.MESSAGING_SYSTEM, "kafka");
span.setData(SpanDataConvention.MESSAGING_DESTINATION_NAME, record.topic());
span.setData(SpanDataConvention.MESSAGING_SYSTEM, "kafka");
span.setData(SpanDataConvention.MESSAGING_DESTINATION_NAME, record.topic());

try {
injectHeaders(record.headers(), span);

span.setStatus(SpanStatus.OK);
span.finish();
} catch (Throwable ignored) {
Comment on lines +62 to 72
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: If injectHeaders() throws an exception in onSend(), the created span is never finished, causing a span leak. The catch block bypasses the span.finish() call.
Severity: MEDIUM

Suggested Fix

Ensure span.finish() is always called after a span is created, even if an exception occurs. This can be done by moving the span creation and finishing logic into a try-finally block, ensuring span.finish() is called in the finally section.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/kafka/SentryProducerInterceptor.java#L56-L72

Potential issue: In `SentryProducerInterceptor.onSend()`, the refactored exception
handling introduces a potential span leak. The `span.finish()` call is now inside a
`try` block. If `injectHeaders()` throws an exception, control will jump to the `catch`
block, skipping the `span.finish()` call. The `catch` block does not finish the span,
causing it to remain unfinished in the parent transaction's span list. This is a
regression from the previous code, which correctly ensured the span was always finished
by placing the call outside the `try` block for header injection.

Did we get this right? ๐Ÿ‘ / ๐Ÿ‘Ž to inform future reviews.

// Header injection must not break the send
// Instrumentation must never break the customer's Kafka send
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as in the original, should we log anything here?

}

span.setStatus(SpanStatus.OK);
span.finish();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Span leaks unfinished when exception occurs after creation

Medium Severity

If an exception is thrown by setData(), injectHeaders(), or setStatus() after startChild() successfully creates a span, the catch block swallows the exception but never calls span.finish(). This leaves an orphaned, unfinished span. This is a regression from the previous code where injectHeaders failures were caught independently and span.finish() still ran. The pattern used elsewhere in this codebase (e.g., SentryCacheWrapper) uses finally { span.finish() } to guarantee cleanup.

Fix in Cursorย Fix in Web

Reviewed by Cursor Bugbot for commit 6d91bdc. Configure here.

return record;
}

Expand Down
Loading