Skip to content

Commit 7ad544f

Browse files
ericapisaniclaude
andcommitted
fix(dedupe): Avoid retaining strong references to user exceptions
DedupeIntegration stored the original exception instance as a fallback when `weakref.ref(exc)` failed (e.g. for builtin exception types). That meant a reference to every such exception lived on the context var until the next exception replaced it, potentially pinning large traceback frames, locals, and user objects in memory. Instead, fall back to a `(type, hash(args))` fingerprint so dedupe can still suppress duplicates without keeping the exception alive. Refs PY-2381 Co-Authored-By: Claude Opus 4.7 <[email protected]>
1 parent e476bf5 commit 7ad544f

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

sentry_sdk/integrations/dedupe.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,25 @@
88
from typing import TYPE_CHECKING
99

1010
if TYPE_CHECKING:
11-
from typing import Optional
11+
from typing import Optional, Tuple, Type, Any
1212

1313
from sentry_sdk._types import Event, Hint
1414

1515

16+
def _safe_args_hash(args: "Tuple[Any, ...]") -> int:
17+
try:
18+
return hash(args)
19+
except Exception:
20+
try:
21+
return hash(repr(args))
22+
except Exception:
23+
return 0
24+
25+
26+
def _fingerprint(exc: BaseException) -> "Tuple[Type[BaseException], int]":
27+
return (type(exc), _safe_args_hash(exc.args))
28+
29+
1630
class DedupeIntegration(Integration):
1731
identifier = "dedupe"
1832

@@ -35,22 +49,23 @@ def processor(event: "Event", hint: "Optional[Hint]") -> "Optional[Event]":
3549
return event
3650

3751
last_seen = integration._last_seen.get(None)
38-
if last_seen is not None:
39-
# last_seen is either a weakref or the original instance
40-
last_seen = (
41-
last_seen() if isinstance(last_seen, weakref.ref) else last_seen
42-
)
43-
4452
exc = exc_info[1]
45-
if last_seen is exc:
53+
54+
is_duplicate = False
55+
if isinstance(last_seen, weakref.ref):
56+
is_duplicate = last_seen() is exc
57+
elif isinstance(last_seen, tuple):
58+
is_duplicate = last_seen == _fingerprint(exc)
59+
60+
if is_duplicate:
4661
logger.info("DedupeIntegration dropped duplicated error event %s", exc)
4762
return None
4863

4964
# we can only weakref non builtin types
5065
try:
5166
integration._last_seen.set(weakref.ref(exc))
5267
except TypeError:
53-
integration._last_seen.set(exc)
68+
integration._last_seen.set(_fingerprint(exc))
5469

5570
return event
5671

0 commit comments

Comments
 (0)