Investigating an error tracking issue When a user asks "what's going on with this error?" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause. Available tools | Tool | Purpose | | ------------------------------------------- | ------------------------------------------------------------------------------------------- | | | Compact issue details (status, assignee, top frame, release, aggregates) | | | Sampled events with stack, URL, browser, | | | Breakdowns, release /…

)\n AND timestamp >= toDateTime('\u003cerror_timestamp>', 'UTC') - INTERVAL 1 HOUR\n AND timestamp \u003c= toDateTime('\u003cerror_timestamp>', 'UTC') + INTERVAL 1 HOUR\nORDER BY timestamp ASC\nLIMIT 100\n```\n\nThe `left(event, 1) != '

Investigating an error tracking issue When a user asks "what's going on with this error?" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause. Available tools | Tool | Purpose | | ------------------------------------------- | ------------------------------------------------------------------------------------------- | | | Compact issue details (status, assignee, top frame, release, aggregates) | | | Sampled events with stack, URL, browser, | | | Breakdowns, release /…

` clause drops PostHog autocapture / system events\nwhile keeping every custom event. The `OR event = '$pageview'`/`'$exception'`\nexceptions re-add the two system events worth seeing on the timeline. This is\nthe same filter the ET UI uses.\n\nMixed `$lib` values in the output are a feature, not noise. When a server SDK\npropagates `$session_id` from the client request (PostHog's own backend does\nthis), the timeline shows server-side activity inline with the browser side —\n\"both SDKs when available\" for free. Skim the lib column to see how each row\nwas produced.\n\nThe skill defaults to a ±1h window because that's what the UI uses; widen it\nwhen an issue's actions are slow (long batch jobs, background workers) or\ntighten it when only the seconds right before the throw matter.\n\n#### 5b. Console logs (web / React Native session replay)\n\nWhen session replay is enabled, the replay pipeline emits `console.*` calls\ninto the `log_entries` table tagged with the same session id. Pull them with\nthe matching window:\n\n```sql\nposthog:execute-sql\nSELECT timestamp, level, message\nFROM log_entries\nWHERE log_source = 'session_replay'\n AND log_source_id = '\u003csession_id_from_step_2>'\n AND timestamp >= toDateTime('\u003cerror_timestamp>', 'UTC') - INTERVAL 1 HOUR\n AND timestamp \u003c= toDateTime('\u003cerror_timestamp>', 'UTC') + INTERVAL 1 HOUR\nORDER BY timestamp ASC\nLIMIT 200\n```\n\n`log_source = 'session_replay'` is the discriminator — `log_entries` is shared\nwith other sources. Empty results are common: either replay isn't enabled, or\nthis specific session wasn't recorded. Mention that in the synthesis rather\nthan treating it as a failure.\n\n#### 5c. Server logs around the error (OTEL via `query-logs`)\n\nFor server-side exceptions, correlate the exception timestamp with OTEL log\nentries the customer ingests. Many projects don't ingest logs at all — if\n`query-logs` returns nothing or errors, say so and move on. Discover available\nservices first with `logs-attribute-values-list` when you don't know which\nservice produced the error.\n\n```json\nposthog:query-logs\n{\n \"query\": {\n \"dateRange\": {\n \"date_from\": \"\u003cerror_timestamp minus 5 minutes>\",\n \"date_to\": \"\u003cerror_timestamp plus 5 minutes>\"\n },\n \"severityLevels\": [\"error\", \"warn\"],\n \"serviceNames\": [\"\u003cservice.name if known>\"],\n \"limit\": 50,\n \"orderBy\": \"earliest\"\n }\n}\n```\n\nCaveats worth knowing before relying on this output:\n\n- Logs are ingested separately from events and typically have shorter retention.\n Old exceptions may return empty even though the issue is still active.\n- `trace_id` / `span_id` come back zero-padded (`\"00000000...\"`) when not set.\n Trace-based correlation only works for explicitly instrumented requests, not\n for every event.\n- `service.name` is a resource attribute. Narrow with `serviceNames` rather\n than a free-text `searchTerm` when you know the producer.\n\n#### 5d. Find a representative replay\n\nHand off to `finding-replay-for-issue` when picking the _best_ session matters —\npopular issues link hundreds of recordings, mostly short crash fragments or\nidle-tab sessions, and that skill applies the duration / active-time / recency\nranking that finds the one most likely to show the cause. Hand off too when the\nuser asks for \"a replay\" without specifying which.\n\nSkip the hand-off and pull a recording inline via `query-session-recordings-list`\nwith `session_ids` from the sample exception events you already fetched in step 2\nwhen only a handful of sessions are linked, the user already named a specific\nsession, or any working example will do (e.g. proving the error reproduces).\n\nIf neither path returns a recording, mention that session replay may not be\nenabled for the affected users — useful context, not a failure.\n\n### Step 6 — Synthesize\n\nPresent in this order:\n\n1. **What it is** — type, message, where in the stack\n2. **Who it affects** — total users, sessions, and any segment breakdown that\n stood out\n3. **When it started** — `first_seen`, plus the release / version that\n introduced it if a breakdown found one\n4. **Likely cause** — one or two hypotheses backed by the breakdowns above\n5. **Next step** — a concrete action: investigate the suspected release, watch\n the linked replay, ping the assignee, or escalate\n\nKeep the synthesis tight. The user wants the answer, not a tour of the data.\n\n## Tips\n\n- The canonical join key from events to an issue is the resolved `issue_id`\n virtual field, with `properties.$exception_issue_id` as fallback — see Step 3\n for the reason and the `build_issue_where` pattern.\n- For a \"what version introduced this?\" breakdown, prefer `$app_version` (the\n user's deployed app version, auto-captured on iOS / React Native and\n manually set on web / server) or `$exception_releases` when populated. Avoid\n `$lib_version` for this question — it's the PostHog SDK library version, not\n the user's app. See the \"Picking the right version property\" subsection in\n Step 3.\n- If the issue spans more than 30 days, widen the date range explicitly.\n Defaults often truncate the original `first_seen` event off the breakdown.\n- Don't propose a fix in the synthesis unless the cause is obvious from the\n sample stack. Hypotheses backed by data are more useful than confident\n guesses.\n- If `query-error-tracking-issue` returns an `external_issues` array, the issue\n is already linked to a Linear / Jira / GitHub ticket. Mention the link in the\n synthesis so the user doesn't open a duplicate.\n---","attachment_filenames":[],"attachments":[],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Investigating an error tracking issue","type":"text"}]},{"type":"paragraph","content":[{"text":"When a user asks \"what's going on with this error?\" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Available tools","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:query-error-tracking-issue","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Compact issue details (status, assignee, top frame, release, aggregates)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:query-error-tracking-issue-events","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sampled ","type":"text"},{"text":"$exception","type":"text","marks":[{"type":"code_inline"}]},{"text":" events with stack, URL, browser, ","type":"text"},{"text":"$session_id","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:execute-sql","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Breakdowns, release / flag correlations, surrounding events + console logs around the error","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:query-logs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OTEL log entries around the error timestamp for server-side issues","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:query-session-recordings-list","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Linked replays (delegate ranking to ","type":"text"},{"text":"finding-replay-for-issue","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"posthog:read-data-schema","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Confirm property keys before filtering on them","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1 — Establish the issue baseline","type":"text"}]},{"type":"paragraph","content":[{"text":"Fetch the issue record with its compact aggregates and a sparkline:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"posthog:query-error-tracking-issue\n{\n \"issueId\": \"\u003cissue_id>\",\n \"dateRange\": { \"date_from\": \"-30d\" },\n \"includeSparkline\": true,\n \"volumeResolution\": 12\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Capture: ","type":"text"},{"text":"name","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"description","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"last_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"assignee","type":"text","marks":[{"type":"code_inline"}]},{"text":", total ","type":"text"},{"text":"occurrences","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"users","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"sessions","type":"text","marks":[{"type":"code_inline"}]},{"text":", top in-app frame, latest release metadata, and the volume buckets.","type":"text"}]},{"type":"paragraph","content":[{"text":"The sparkline tells you the shape — flat, spike, ramp, or recurring — and that shape drives the rest of the investigation. If the user only asked a status question, skip ","type":"text"},{"text":"includeSparkline","type":"text","marks":[{"type":"code_inline"}]},{"text":" to save tokens.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2 — Pull a sample exception event","type":"text"}]},{"type":"paragraph","content":[{"text":"A captured event has the stack frames, URL, browser, and properties needed to reason about cause. Pull a recent sample first, then an early one to compare.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"posthog:query-error-tracking-issue-events\n{\n \"issueId\": \"\u003cissue_id>\",\n \"limit\": 1,\n \"verbosity\": \"stack\"\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"verbosity: \"raw\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" only if the truncated stack hides the answer. The tool defaults to ","type":"text"},{"text":"onlyAppFrames: true","type":"text","marks":[{"type":"code_inline"}]},{"text":", which strips vendor frames; flip to ","type":"text"},{"text":"false","type":"text","marks":[{"type":"code_inline"}]},{"text":" when the bug appears to live in a third-party library — or when the response comes back with ","type":"text"},{"text":"stacktrace.type: \"resolved\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" but no frames at all (common for minified bundles where every frame looks vendor-y to the resolver, e.g. React production builds).","type":"text"}]},{"type":"paragraph","content":[{"text":"For the earliest sample, narrow ","type":"text"},{"text":"dateRange","type":"text","marks":[{"type":"code_inline"}]},{"text":" to a tight window around the issue's ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":" (e.g. set ","type":"text"},{"text":"date_from","type":"text","marks":[{"type":"code_inline"}]},{"text":" slightly before and ","type":"text"},{"text":"date_to","type":"text","marks":[{"type":"code_inline"}]},{"text":" slightly after) and pass ","type":"text"},{"text":"orderDirection: \"ASC\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" so you get the earliest event in the window rather than the latest — the tool defaults to ","type":"text"},{"text":"DESC","type":"text","marks":[{"type":"code_inline"}]},{"text":", which would return a recent event and silently duplicate the first call. If recent and earliest events look materially different — different stack root, different URL pattern — the issue may be a grouping mistake. Flag for ","type":"text"},{"text":"grouping-noisy-errors","type":"text","marks":[{"type":"code_inline"}]},{"text":" instead of continuing as if it were one bug.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3 — Run breakdowns to isolate the cause","type":"text"}]},{"type":"paragraph","content":[{"text":"Breakdowns aren't a typed tool — drop into ","type":"text"},{"text":"execute-sql","type":"text","marks":[{"type":"code_inline"}]},{"text":". Run only the breakdowns the issue's shape suggests; each one costs a query and clutters the synthesis.","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sparkline shape","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"First breakdown to try","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Spike from zero","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"By app version / release — almost always a deploy regression (see below)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Steady-state high","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"By browser / OS — rendering or platform-specific bug","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ramp","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"By geography or feature flag — gradual rollout exposure","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Bursts then quiet","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"By time of day or ","type":"text"},{"text":"$current_url","type":"text","marks":[{"type":"code_inline"}]},{"text":" — scheduled job or specific page","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"Picking the right version property","type":"text"}]},{"type":"paragraph","content":[{"text":"PostHog emits three version-shaped fields. They mean different things and only one of them answers \"what version of the user's app introduced this?\":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Property","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"What it is","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Auto-captured by","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use for","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cymbal-managed release map, keyed by release ID","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Only when SDK publishes release metadata (e.g. sourcemap upload tied to a release)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Most precise release attribution ","type":"text"},{"text":"when present","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"$app_version","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"The user's deployed app version","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"iOS (","type":"text"},{"text":"CFBundleShortVersionString","type":"text","marks":[{"type":"code_inline"}]},{"text":"), React Native (Expo / react-native-device-info)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"What deploy of my app introduced this?\" — the question users care about","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"$lib_version","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"The PostHog SDK library version (e.g. posthog-js 1.298.0)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Every SDK on every event","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"The narrow \"did upgrading the PostHog SDK introduce this?\" question","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"$lib_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" is on virtually every event, which makes it tempting — but it's the PostHog library version, not the user's app version. A constant ","type":"text"},{"text":"$lib_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" paired with a spike means the user shipped a regression in their own code with the SDK unchanged, which is the common case. Reach for ","type":"text"},{"text":"$lib_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" only when nothing else is populated and you're explicitly asking \"did upgrading PostHog cause this?\".","type":"text"}]},{"type":"paragraph","content":[{"text":"Web / server / Node / Java / Python projects do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" auto-capture ","type":"text"},{"text":"$app_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the customer has to set it (via ","type":"text"},{"text":"register","type":"text","marks":[{"type":"code_inline"}]},{"text":", a context provider, or ","type":"text"},{"text":"before_send","type":"text","marks":[{"type":"code_inline"}]},{"text":"). If the breakdown comes back with one ","type":"text"},{"text":"$app_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" row of all-NULL, say so explicitly in the synthesis and suggest the customer wire it up; falling back to ","type":"text"},{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]},{"text":" or to a per-day timeline by ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":" keeps the investigation moving.","type":"text"}]},{"type":"paragraph","content":[{"text":"Example (","type":"text"},{"text":"$app_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" — populated automatically on mobile, manually on web / server):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"sql"},"content":[{"text":"posthog:execute-sql\nSELECT\n properties.$app_version AS app_version,\n count() AS occurrences,\n uniq(person_id) AS users,\n min(timestamp) AS first_seen,\n max(timestamp) AS last_seen\nFROM events\nWHERE event = '$exception'\n AND (issue_id = '\u003cissue_id>' OR properties.$exception_issue_id = '\u003cissue_id>')\n AND timestamp > now() - INTERVAL 30 DAY\nGROUP BY app_version\nORDER BY occurrences DESC\nLIMIT 20","type":"text"}]},{"type":"paragraph","content":[{"text":"The ","type":"text"},{"text":"(issue_id = ... OR properties.$exception_issue_id = ...)","type":"text","marks":[{"type":"code_inline"}]},{"text":" pattern mirrors the canonical ","type":"text"},{"text":"build_issue_where","type":"text","marks":[{"type":"code_inline"}]},{"text":" clause from ","type":"text"},{"text":"products/error_tracking/backend/api/query_utils.py","type":"text","marks":[{"type":"code_inline"}]},{"text":". ","type":"text"},{"text":"issue_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" is the resolved virtual field on ","type":"text"},{"text":"events","type":"text","marks":[{"type":"code_inline"}]},{"text":" (it follows fingerprint overrides so merged/split issues route correctly); ","type":"text"},{"text":"properties.$exception_issue_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" is the raw event property captured at ingestion. Filtering on only the property silently undercounts events for issues that have been merged or split.","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":" for one ","type":"text"},{"text":"app_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" is much later than the issue's overall ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":", that release introduced or worsened the bug — strong root-cause signal. If every row is ","type":"text"},{"text":"NULL","type":"text","marks":[{"type":"code_inline"}]},{"text":", the SDK isn't reporting an app version on this project (common on web / server) — switch to ","type":"text"},{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]},{"text":" if the customer ships releases, or fall back to a ","type":"text"},{"text":"toDate(timestamp)","type":"text","marks":[{"type":"code_inline"}]},{"text":" timeline.","type":"text"}]},{"type":"paragraph","content":[{"text":"When ","type":"text"},{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]},{"text":" is populated, it's a JSON dict keyed by release ID. There is no top-level ","type":"text"},{"text":"$release","type":"text","marks":[{"type":"code_inline"}]},{"text":" property; query ","type":"text"},{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]},{"text":" directly when you need release attribution and the customer has it wired up.","type":"text"}]},{"type":"paragraph","content":[{"text":"Repeat with ","type":"text"},{"text":"properties.$browser","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"properties.$os","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"properties.$current_url","type":"text","marks":[{"type":"code_inline"}]},{"text":", or any feature flag the project tags errors with.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4 — Check feature flag exposure","type":"text"}]},{"type":"paragraph","content":[{"text":"If the user suspects an experiment or rollout, check whether affected users had a flag enabled when the error fired.","type":"text"}]},{"type":"paragraph","content":[{"text":"To enumerate which flags were evaluated on affected users, parse the ","type":"text"},{"text":"$active_feature_flags","type":"text","marks":[{"type":"code_inline"}]},{"text":" property — it is materialized as a JSON-encoded string in ClickHouse, so ","type":"text"},{"text":"arrayJoin(properties.$active_feature_flags)","type":"text","marks":[{"type":"code_inline"}]},{"text":" directly will fail; ","type":"text"},{"text":"JSONExtract","type":"text","marks":[{"type":"code_inline"}]},{"text":" is the working pattern:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"sql"},"content":[{"text":"posthog:execute-sql\nSELECT\n arrayJoin(JSONExtract(toString(properties.$active_feature_flags), 'Array(String)')) AS flag,\n count() AS occurrences,\n uniq(person_id) AS users\nFROM events\nWHERE event = '$exception'\n AND (issue_id = '\u003cissue_id>' OR properties.$exception_issue_id = '\u003cissue_id>')\n AND timestamp > now() - INTERVAL 14 DAY\n AND notEmpty(toString(properties.$active_feature_flags))\nGROUP BY flag\nORDER BY occurrences DESC\nLIMIT 20","type":"text"}]},{"type":"paragraph","content":[{"text":"Caveat: every event captures every evaluated flag key, so this enumeration often returns identical counts across flags and ","type":"text"},{"text":"doesn't tell you which flag correlates with the error","type":"text","marks":[{"type":"strong"}]},{"text":" — only which were on the user. To actually test a hypothesis, query the per-flag value column ","type":"text"},{"text":"properties.$feature/\u003cflag-key>","type":"text","marks":[{"type":"code_inline"}]},{"text":", which carries the evaluated value (","type":"text"},{"text":"true","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"false","type":"text","marks":[{"type":"code_inline"}]},{"text":"/variant name):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"sql"},"content":[{"text":"posthog:execute-sql\nSELECT\n properties.`$feature/my-flag-key` AS variant,\n count() AS occurrences,\n uniq(person_id) AS users\nFROM events\nWHERE event = '$exception'\n AND (issue_id = '\u003cissue_id>' OR properties.$exception_issue_id = '\u003cissue_id>')\n AND timestamp > now() - INTERVAL 14 DAY\nGROUP BY variant\nORDER BY occurrences DESC","type":"text"}]},{"type":"paragraph","content":[{"text":"Compare the variant split here to the project's overall exposure on the same flag in the same window. Disproportionate representation of one variant suggests the flag is involved in the cause — not a guarantee, but a strong hypothesis.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5 — Reconstruct what happened around the error","type":"text"}]},{"type":"paragraph","content":[{"text":"Use the ","type":"text"},{"text":"$session_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" from the sample event in step 2 to pull the activity surrounding the exception. Three sources stack on each other; run the ones that make sense for the SDK that captured the error.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"5a. Surrounding events (client SDKs by ","type":"text"},{"text":"$session_id","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"paragraph","content":[{"text":"Mirrors the ET frontend session timeline. Pulls custom events, page views, and other exceptions captured under the same session within a ±1h window:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"sql"},"content":[{"text":"posthog:execute-sql\nSELECT\n uuid,\n event,\n timestamp,\n properties.$lib AS lib,\n properties.$current_url AS url\nFROM events\nWHERE $session_id = '\u003csession_id_from_step_2>'\n AND (event = '$exception' OR event = '$pageview' OR left(event, 1) != '

Investigating an error tracking issue When a user asks "what's going on with this error?" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause. Available tools | Tool | Purpose | | ------------------------------------------- | ------------------------------------------------------------------------------------------- | | | Compact issue details (status, assignee, top frame, release, aggregates) | | | Sampled events with stack, URL, browser, | | | Breakdowns, release /…

)\n AND timestamp >= toDateTime('\u003cerror_timestamp>', 'UTC') - INTERVAL 1 HOUR\n AND timestamp \u003c= toDateTime('\u003cerror_timestamp>', 'UTC') + INTERVAL 1 HOUR\nORDER BY timestamp ASC\nLIMIT 100","type":"text"}]},{"type":"paragraph","content":[{"text":"The ","type":"text"},{"text":"left(event, 1) != '

Investigating an error tracking issue When a user asks "what's going on with this error?" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause. Available tools | Tool | Purpose | | ------------------------------------------- | ------------------------------------------------------------------------------------------- | | | Compact issue details (status, assignee, top frame, release, aggregates) | | | Sampled events with stack, URL, browser, | | | Breakdowns, release /…

","type":"text","marks":[{"type":"code_inline"}]},{"text":" clause drops PostHog autocapture / system events while keeping every custom event. The ","type":"text"},{"text":"OR event = '$pageview'","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"'$exception'","type":"text","marks":[{"type":"code_inline"}]},{"text":" exceptions re-add the two system events worth seeing on the timeline. This is the same filter the ET UI uses.","type":"text"}]},{"type":"paragraph","content":[{"text":"Mixed ","type":"text"},{"text":"$lib","type":"text","marks":[{"type":"code_inline"}]},{"text":" values in the output are a feature, not noise. When a server SDK propagates ","type":"text"},{"text":"$session_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" from the client request (PostHog's own backend does this), the timeline shows server-side activity inline with the browser side — \"both SDKs when available\" for free. Skim the lib column to see how each row was produced.","type":"text"}]},{"type":"paragraph","content":[{"text":"The skill defaults to a ±1h window because that's what the UI uses; widen it when an issue's actions are slow (long batch jobs, background workers) or tighten it when only the seconds right before the throw matter.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"5b. Console logs (web / React Native session replay)","type":"text"}]},{"type":"paragraph","content":[{"text":"When session replay is enabled, the replay pipeline emits ","type":"text"},{"text":"console.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" calls into the ","type":"text"},{"text":"log_entries","type":"text","marks":[{"type":"code_inline"}]},{"text":" table tagged with the same session id. Pull them with the matching window:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"sql"},"content":[{"text":"posthog:execute-sql\nSELECT timestamp, level, message\nFROM log_entries\nWHERE log_source = 'session_replay'\n AND log_source_id = '\u003csession_id_from_step_2>'\n AND timestamp >= toDateTime('\u003cerror_timestamp>', 'UTC') - INTERVAL 1 HOUR\n AND timestamp \u003c= toDateTime('\u003cerror_timestamp>', 'UTC') + INTERVAL 1 HOUR\nORDER BY timestamp ASC\nLIMIT 200","type":"text"}]},{"type":"paragraph","content":[{"text":"log_source = 'session_replay'","type":"text","marks":[{"type":"code_inline"}]},{"text":" is the discriminator — ","type":"text"},{"text":"log_entries","type":"text","marks":[{"type":"code_inline"}]},{"text":" is shared with other sources. Empty results are common: either replay isn't enabled, or this specific session wasn't recorded. Mention that in the synthesis rather than treating it as a failure.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"5c. Server logs around the error (OTEL via ","type":"text"},{"text":"query-logs","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"paragraph","content":[{"text":"For server-side exceptions, correlate the exception timestamp with OTEL log entries the customer ingests. Many projects don't ingest logs at all — if ","type":"text"},{"text":"query-logs","type":"text","marks":[{"type":"code_inline"}]},{"text":" returns nothing or errors, say so and move on. Discover available services first with ","type":"text"},{"text":"logs-attribute-values-list","type":"text","marks":[{"type":"code_inline"}]},{"text":" when you don't know which service produced the error.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"posthog:query-logs\n{\n \"query\": {\n \"dateRange\": {\n \"date_from\": \"\u003cerror_timestamp minus 5 minutes>\",\n \"date_to\": \"\u003cerror_timestamp plus 5 minutes>\"\n },\n \"severityLevels\": [\"error\", \"warn\"],\n \"serviceNames\": [\"\u003cservice.name if known>\"],\n \"limit\": 50,\n \"orderBy\": \"earliest\"\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Caveats worth knowing before relying on this output:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Logs are ingested separately from events and typically have shorter retention. Old exceptions may return empty even though the issue is still active.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"trace_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"span_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" come back zero-padded (","type":"text"},{"text":"\"00000000...\"","type":"text","marks":[{"type":"code_inline"}]},{"text":") when not set. Trace-based correlation only works for explicitly instrumented requests, not for every event.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"service.name","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a resource attribute. Narrow with ","type":"text"},{"text":"serviceNames","type":"text","marks":[{"type":"code_inline"}]},{"text":" rather than a free-text ","type":"text"},{"text":"searchTerm","type":"text","marks":[{"type":"code_inline"}]},{"text":" when you know the producer.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"5d. Find a representative replay","type":"text"}]},{"type":"paragraph","content":[{"text":"Hand off to ","type":"text"},{"text":"finding-replay-for-issue","type":"text","marks":[{"type":"code_inline"}]},{"text":" when picking the ","type":"text"},{"text":"best","type":"text","marks":[{"type":"em"}]},{"text":" session matters — popular issues link hundreds of recordings, mostly short crash fragments or idle-tab sessions, and that skill applies the duration / active-time / recency ranking that finds the one most likely to show the cause. Hand off too when the user asks for \"a replay\" without specifying which.","type":"text"}]},{"type":"paragraph","content":[{"text":"Skip the hand-off and pull a recording inline via ","type":"text"},{"text":"query-session-recordings-list","type":"text","marks":[{"type":"code_inline"}]},{"text":" with ","type":"text"},{"text":"session_ids","type":"text","marks":[{"type":"code_inline"}]},{"text":" from the sample exception events you already fetched in step 2 when only a handful of sessions are linked, the user already named a specific session, or any working example will do (e.g. proving the error reproduces).","type":"text"}]},{"type":"paragraph","content":[{"text":"If neither path returns a recording, mention that session replay may not be enabled for the affected users — useful context, not a failure.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 6 — Synthesize","type":"text"}]},{"type":"paragraph","content":[{"text":"Present in this order:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What it is","type":"text","marks":[{"type":"strong"}]},{"text":" — type, message, where in the stack","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Who it affects","type":"text","marks":[{"type":"strong"}]},{"text":" — total users, sessions, and any segment breakdown that stood out","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When it started","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":", plus the release / version that introduced it if a breakdown found one","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Likely cause","type":"text","marks":[{"type":"strong"}]},{"text":" — one or two hypotheses backed by the breakdowns above","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Next step","type":"text","marks":[{"type":"strong"}]},{"text":" — a concrete action: investigate the suspected release, watch the linked replay, ping the assignee, or escalate","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Keep the synthesis tight. The user wants the answer, not a tour of the data.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Tips","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The canonical join key from events to an issue is the resolved ","type":"text"},{"text":"issue_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" virtual field, with ","type":"text"},{"text":"properties.$exception_issue_id","type":"text","marks":[{"type":"code_inline"}]},{"text":" as fallback — see Step 3 for the reason and the ","type":"text"},{"text":"build_issue_where","type":"text","marks":[{"type":"code_inline"}]},{"text":" pattern.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For a \"what version introduced this?\" breakdown, prefer ","type":"text"},{"text":"$app_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the user's deployed app version, auto-captured on iOS / React Native and manually set on web / server) or ","type":"text"},{"text":"$exception_releases","type":"text","marks":[{"type":"code_inline"}]},{"text":" when populated. Avoid ","type":"text"},{"text":"$lib_version","type":"text","marks":[{"type":"code_inline"}]},{"text":" for this question — it's the PostHog SDK library version, not the user's app. See the \"Picking the right version property\" subsection in Step 3.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If the issue spans more than 30 days, widen the date range explicitly. Defaults often truncate the original ","type":"text"},{"text":"first_seen","type":"text","marks":[{"type":"code_inline"}]},{"text":" event off the breakdown.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Don't propose a fix in the synthesis unless the cause is obvious from the sample stack. Hypotheses backed by data are more useful than confident guesses.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"query-error-tracking-issue","type":"text","marks":[{"type":"code_inline"}]},{"text":" returns an ","type":"text"},{"text":"external_issues","type":"text","marks":[{"type":"code_inline"}]},{"text":" array, the issue is already linked to a Linear / Jira / GitHub ticket. Mention the link in the synthesis so the user doesn't open a duplicate.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"investigating-error-issue","author":"@skillopedia","source":{"stars":34799,"repo_name":"posthog","origin_url":"https://github.com/posthog/posthog/blob/HEAD/products/error_tracking/skills/investigating-error-issue/SKILL.md","repo_owner":"posthog","body_sha256":"07575ffbe805df288d2de49a33e020792116ec461f6bbee972b6892e25970d10","cluster_key":"e0a81f291cac3fa886b0d6965808e424eaf6eef342c99467b109f7479f525e07","clean_bundle":{"format":"clean-skill-bundle-v1","source":"posthog/posthog/products/error_tracking/skills/investigating-error-issue/SKILL.md","bundle_sha256":"093017158dac7062aee8fb886c1d1b74c92710e61be4d2336e8fa602c5d7a076","attachment_count":0,"text_attachments":0,"binary_attachments":0},"cluster_size":2,"skill_md_path":"products/error_tracking/skills/investigating-error-issue/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"browser-automation-scraping","category_label":"Browser"},"exact_dupes_collapsed_into_this":1},"version":"v1","category":"browser-automation-scraping","import_tag":"clean-skills-v1","description":"Investigates a single PostHog error tracking issue end-to-end. Use when the user provides an issue ID or pastes an issue URL (`/error_tracking/\u003cid>`) and wants to understand the error — who it affects, what triggers it, when it started, whether it correlates with a release, browser, OS, or feature flag, and what the next step should be. Pulls aggregated metrics, sample exception events, segment breakdowns, linked replays, and synthesizes a hypothesis-grade summary in one pass.\n"}},"renderedAt":1782980405990}

Investigating an error tracking issue When a user asks "what's going on with this error?" or pastes an issue URL, gather the context they would otherwise have to assemble manually: who is hitting it, what changed, where it happens, and whether a replay shows the cause. Available tools | Tool | Purpose | | ------------------------------------------- | ------------------------------------------------------------------------------------------- | | | Compact issue details (status, assignee, top frame, release, aggregates) | | | Sampled events with stack, URL, browser, | | | Breakdowns, release /…