Skip to content

fix(capture-exception): keep the stack trace in fatal exception payloads - #124

Merged
turnipdabeets merged 3 commits into
mainfrom
posthog/fatal-payload-keeps-stacktrace
Oct 21, 2026
Merged

turnipdabeets merged 3 commits into
mainfrom
posthog/fatal-payload-keeps-stacktrace

Conversation

@posthog

@posthog posthog Bot commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Why

A fatal crash in posthog-react-native reached PostHog with no stack trace, while the same error captured as handled kept its stack (posthog-js#5287). The capture-exception spec requires a genuine stack trace to be preserved, but it only describes the handled path — it says nothing about the second, stricter serializer an SDK uses for a fatal/crash payload, so nothing forbade that path from silently emitting less for the same exception.

Source change

  • PostHog/posthog-js#5290 — keep the stack trace when a frame has an undefined key (merged to main). The react-native fatal payload builder treated an object member with no value as making the whole object unserializable. Stack frames routinely carry one (chunk_id is unset for any frame whose file is not in the chunk-id map), so a single frame dropped the entire stacktrace and the crash was sent with only type, value and mechanism. The fix makes the check match ordinary JSON serialization, which omits an absent member.

What changed in the spec

New capture-exception requirement Fatal exception payloads keep their exception data (proposed, applied and archived on this branch per AGENTS.md):

  • A separate fatal/crash serializer emits the same SDK-owned exception data as the handled path for the same exception — every $exception_list entry with its stacktrace and frames.
  • An optional field whose value is unset is omitted from the serialized event and SHALL NOT make its containing object unserializable or drop the frame, the stacktrace, or the entry. chunk_id is called out as the common case.
  • Where a size budget applies, $exception_list SHOULD be budgeted separately from caller-supplied custom properties; truncating within the exception data stays allowed.

Scenarios use the prose style of the neighbouring "Ignored exception types" requirement, so no new harness steps are needed. openspec validate --specs --strict totals are unchanged from main (the remaining warnings are the pre-existing long-requirement ones).

Uncertain / worth a look

  • The rule is generalized from one SDK's fix. Only posthog-react-native is known to have a separate size-bounded fatal serializer; iOS and Android serialize crash payloads through their normal event path, so the requirement is written to bind only where such a serializer exists.
  • The separate-budget clause is a SHOULD, inferred from react-native's per-key budgets rather than from an agreed cross-SDK rule — tighten or drop it if you'd rather the spec stay silent on budgets.
  • Not included, flagged for human review: posthog-js#5291 and posthog-python#1057 add trace exemplars to flushed metric series (identical OTLP/JSON wire shape in both). There is no metrics capability on main — the spec is still open in Add metrics capability spec #30, with docs: add network timing to metrics spec #66 stacked on it — so there is no home for this yet.
  • Still parked, unchanged from #119: posthog-python's capture-v1 series continued this week on its unreleased v1 branch (per-event options, global/context option layers, personless as an event option, AI lane on the async client). It reshapes capture's option/property layering for server SDKs and needs a deliberate call, not an inferred spec edit.

Created with PostHog Desktop

🤖 Generated with Claude Code

A separate fatal/crash payload serializer must emit the same SDK-owned exception data as the handled path: an optional field with no value is omitted on the wire, not a reason to drop the frame, the stacktrace, or the $exception_list entry.

Co-Authored-By: Claude Opus 5 <[email protected]>

Generated-By: PostHog Desktop
Task-Id: 6906e191-b1ef-46ca-a159-8620f4ba9e66
…llow dropping an oversized stacktrace

Matches react-native boundedObject, which drops a stacktrace that alone exceeds the budget.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@turnipdabeets
turnipdabeets marked this pull request as ready for review October 20, 2026 19:47
@turnipdabeets
turnipdabeets requested a review from a team as a code owner October 20, 2026 19:47

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated advisory code review.

Comment thread openspec/specs/capture-exception/spec.md
@marandaneto
marandaneto requested a review from a team October 21, 2026 14:29
…al parity

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@turnipdabeets
turnipdabeets merged commit d9b90a8 into main Oct 21, 2026
7 checks passed
@turnipdabeets
turnipdabeets deleted the posthog/fatal-payload-keeps-stacktrace branch October 21, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants