feat(error-tracking): standardize exception event metadata - #898
feat(error-tracking): standardize exception event metadata#898hpouillot wants to merge 3 commits into
Conversation
posthog-python Compliance ReportDate: 2026-08-26 10:13:13 UTC ✅ All Tests Passed!111/111 tests passed Capture_V1 Tests✅ 94/94 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
Prompt To Fix All With AI### Issue 1
posthog/exception_utils.py:696-698
**Repeated members are omitted**
When an exception object occupies multiple valid positions in an `ExceptionGroup` tree, the shared `seen_exception_ids` set discards every occurrence after the first, causing `$exception_list` to omit members and report incomplete group structure.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(error-tracking): preserve explicit t..." | Re-trigger Greptile |
| if id(exc_value) in seen_exception_ids or exception_id >= 50: | ||
| return (exception_id, []) | ||
| seen_exception_ids.add(id(exc_value)) |
There was a problem hiding this comment.
When an exception object occupies multiple valid positions in an ExceptionGroup tree, the shared seen_exception_ids set discards every occurrence after the first, causing $exception_list to omit members and report incomplete group structure.
Knowledge Base Used: Event payload processing
Prompt To Fix With AI
This is a comment left during a code review.
Path: posthog/exception_utils.py
Line: 696-698
Comment:
**Repeated members are omitted**
When an exception object occupies multiple valid positions in an `ExceptionGroup` tree, the shared `seen_exception_ids` set discards every occurrence after the first, causing `$exception_list` to omit members and report incomplete group structure.
**Knowledge Base Used:** [Event payload processing](https://app.greptile.com/posthog-org-19734/-/custom-context/knowledge-base/posthog/posthog-python/-/docs/event-payload-processing.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
This is intentional for the canonical exception graph contract: the same exception object must not be serialized more than once, including when it is referenced by multiple ExceptionGroup positions. The shared identity set also provides cycle safety. I added a regression test covering a repeated group member in 0fbbfc4.
marandaneto
left a comment
There was a problem hiding this comment.
Automated advisory code review.
|
|
||
| is_exception_group = BaseExceptionGroup is not None and isinstance( | ||
| exc_value, BaseExceptionGroup | ||
| (_, exceptions) = _exceptions_from_error( |
There was a problem hiding this comment.
blocking: Restrict group traversal to actual exception groups — Routing every exception through _exceptions_from_error now exposes ordinary exceptions to its hasattr(exc_value, "exceptions") group heuristic. A custom exception with an unrelated non-iterable exceptions attribute raises TypeError, which Client.capture_exception swallows and consequently drops the event; an iterable value instead creates phantom child exceptions. Previously, non-BaseExceptionGroup exceptions used walk_exception_chain and avoided this branch, so group-member traversal must remain restricted to actual BaseExceptionGroup instances.
|
This change introduces backwards-incompatible public schema/API/contract changes: Reserved exception properties supplied through capture_exception(..., properties=...) can no longer override SDK-generated or processor-owned values. If thats intentional, thats ok, but i think its not as designed, user provided props should always win |
💡 Motivation and Context
Standardize Python exception events with the cross-SDK metadata contract so severity, capture source, mechanism semantics, nested linkage, and reserved property ownership are predictable.
Canonical contract: https://github.com/PostHog/sdk-specs/blob/main/openspec/specs/exception-event-metadata/spec.md
💚 How did you test it?
📝 Checklist
If releasing new changes
sampo addto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Implemented with pi from the shared OpenSpec contract. Integration-only capture metadata is kept out of the public API while manual and automatic capture paths preserve their existing behavior.