Skip to content

.

eec68c4
Select commit
Loading
Failed to load commit list.
Merged

fix(logging): Fix deadlock in log batcher #5684

.
eec68c4
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: find-bugs completed Mar 17, 2026 in 2m 10s

2 issues

find-bugs: Found 2 issues (2 medium)

Medium

flush() method lacks re-entry guard, causing protection to be incorrectly reset - `sentry_sdk/_batcher.py:117-122`

The flush() method unconditionally sets self._active.flag = True and resets it to False in the finally block, without first checking if the flag was already set. If flush() is called while _flush_loop() is running on the same thread (which permanently sets _active.flag = True), the finally block will incorrectly reset the flag to False, defeating the deadlock protection. This could allow a subsequent add() call to proceed and attempt to acquire locks that are already held.

Re-entry flag not cleared on early return, permanently dropping all spans from thread - `sentry_sdk/_span_batcher.py:65-66`

When _ensure_thread() returns False or _flusher is None at lines 65-66, the method returns without clearing self._active.flag. Since the flag is set at line 63 before the try block that contains the finally to reset it, this early return path leaves the flag permanently True for the current thread. All subsequent add() calls from that thread will be silently discarded. The base class _batcher.py correctly places this check inside the try block (lines 94-96), ensuring the finally always runs.


Duration: 2m 2s · Tokens: 302.1k in / 6.4k out · Cost: $0.50 (+extraction: $0.00, +merge: $0.00, +fix_gate: $0.00)

Annotations

Check warning on line 122 in sentry_sdk/_batcher.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

flush() method lacks re-entry guard, causing protection to be incorrectly reset

The `flush()` method unconditionally sets `self._active.flag = True` and resets it to `False` in the finally block, without first checking if the flag was already set. If `flush()` is called while `_flush_loop()` is running on the same thread (which permanently sets `_active.flag = True`), the finally block will incorrectly reset the flag to `False`, defeating the deadlock protection. This could allow a subsequent `add()` call to proceed and attempt to acquire locks that are already held.

Check warning on line 66 in sentry_sdk/_span_batcher.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

Re-entry flag not cleared on early return, permanently dropping all spans from thread

When `_ensure_thread()` returns False or `_flusher is None` at lines 65-66, the method returns without clearing `self._active.flag`. Since the flag is set at line 63 **before** the `try` block that contains the `finally` to reset it, this early return path leaves the flag permanently True for the current thread. All subsequent `add()` calls from that thread will be silently discarded. The base class `_batcher.py` correctly places this check **inside** the `try` block (lines 94-96), ensuring the `finally` always runs.