investigating-error-issue

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
当用户询问“这个错误是怎么回事?”或粘贴问题URL时,收集他们原本需要手动整理的上下文信息:哪些用户遇到了该错误、发生了哪些变化、错误出现的场景,以及会话重放是否能展示错误原因。

Available tools

可用工具

ToolPurpose
posthog:query-error-tracking-issue
Compact issue details (status, assignee, top frame, release, aggregates)
posthog:query-error-tracking-issue-events
Sampled
$exception
events with stack, URL, browser,
$session_id
posthog:execute-sql
Breakdowns, release / flag correlations, surrounding events + console logs around the error
posthog:query-logs
OTEL log entries around the error timestamp for server-side issues
posthog:query-session-recordings-list
Linked replays (delegate ranking to
finding-replay-for-issue
)
posthog:read-data-schema
Confirm property keys before filtering on them
工具名称用途
posthog:query-error-tracking-issue
获取问题的精简详情(状态、负责人、顶级调用栈、版本发布、聚合数据)
posthog:query-error-tracking-issue-events
获取带调用栈、URL、浏览器、
$session_id
的采样
$exception
事件
posthog:execute-sql
生成细分维度数据、版本/功能标志关联分析、错误发生前后的事件及控制台日志
posthog:query-logs
获取服务器端错误发生时间附近的OTEL日志条目
posthog:query-session-recordings-list
获取关联的会话重放(由
finding-replay-for-issue
负责排序)
posthog:read-data-schema
在过滤前确认属性键的有效性

Workflow

工作流程

Step 1 — Establish the issue baseline

步骤1 — 建立问题基准线

Fetch the issue record with its compact aggregates and a sparkline:
json
posthog:query-error-tracking-issue
{
  "issueId": "<issue_id>",
  "dateRange": { "date_from": "-30d" },
  "includeSparkline": true,
  "volumeResolution": 12
}
Capture:
name
,
description
,
status
,
first_seen
,
last_seen
,
assignee
, total
occurrences
/
users
/
sessions
, top in-app frame, latest release metadata, and the volume buckets.
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
includeSparkline
to save tokens.
获取包含聚合数据和趋势图的问题记录:
json
posthog:query-error-tracking-issue
{
  "issueId": "<issue_id>",
  "dateRange": { "date_from": "-30d" },
  "includeSparkline": true,
  "volumeResolution": 12
}
记录以下信息:
name
description
status
first_seen
last_seen
assignee
、总
occurrences
/
users
/
sessions
数量、顶级应用内调用栈、最新版本发布元数据,以及数据量区间。
趋势图能展示错误的变化形态——平稳、激增、递增或周期性出现,这种形态会决定后续的调查方向。如果用户仅询问状态相关问题,可跳过
includeSparkline
以节省资源。

Step 2 — Pull a sample exception event

步骤2 — 获取异常事件样本

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.
json
posthog:query-error-tracking-issue-events
{
  "issueId": "<issue_id>",
  "limit": 1,
  "verbosity": "stack"
}
Use
verbosity: "raw"
only if the truncated stack hides the answer. The tool defaults to
onlyAppFrames: true
, which strips vendor frames; flip to
false
when the bug appears to live in a third-party library — or when the response comes back with
stacktrace.type: "resolved"
but no frames at all (common for minified bundles where every frame looks vendor-y to the resolver, e.g. React production builds).
For the earliest sample, narrow
dateRange
to a tight window around the issue's
first_seen
(e.g. set
date_from
slightly before and
date_to
slightly after) and pass
orderDirection: "ASC"
so you get the earliest event in the window rather than the latest — the tool defaults to
DESC
, 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
grouping-noisy-errors
instead of continuing as if it were one bug.
捕获的事件包含调用栈、URL、浏览器和用于分析原因的属性。先获取最近的样本,再获取早期样本进行对比。
json
posthog:query-error-tracking-issue-events
{
  "issueId": "<issue_id>",
  "limit": 1,
  "verbosity": "stack"
}
仅当截断的调用栈无法显示答案时,才使用
verbosity: "raw"
。该工具默认
onlyAppFrames: true
,会过滤掉第三方库的调用栈;当疑似bug存在于第三方库中,或返回结果显示
stacktrace.type: "resolved"
但无调用栈帧时(压缩后的代码包常见,例如React生产构建中所有帧看起来都像第三方库的),需将该参数设为
false
要获取最早的样本,需将
dateRange
缩小到问题
first_seen
附近的窄窗口(例如将
date_from
设为略早于
first_seen
date_to
设为略晚于
first_seen
),并传递
orderDirection: "ASC"
,这样就能获取窗口内最早的事件而非最新的——工具默认
DESC
,会返回最近的事件,导致与第一次调用结果重复。如果最近和最早的事件存在显著差异(不同的调用栈根、不同的URL模式),则该问题可能是分组错误,应标记为
grouping-noisy-errors
,而非按单一bug继续调查。

Step 3 — Run breakdowns to isolate the cause

步骤3 — 运行细分分析以定位原因

Breakdowns aren't a typed tool — drop into
execute-sql
. Run only the breakdowns the issue's shape suggests; each one costs a query and clutters the synthesis.
Sparkline shapeFirst breakdown to try
Spike from zeroBy app version / release — almost always a deploy regression (see below)
Steady-state highBy browser / OS — rendering or platform-specific bug
RampBy geography or feature flag — gradual rollout exposure
Bursts then quietBy time of day or
$current_url
— scheduled job or specific page
细分分析没有专门的工具,需使用
execute-sql
。仅根据问题的形态运行必要的细分分析,每个分析都会消耗一次查询资源并增加总结的复杂度。
趋势图形态首选的细分分析维度
从零激增按应用版本/发布版本——几乎总是部署导致的回归(见下文)
持续高频率按浏览器/操作系统——渲染或平台特定bug
递增趋势按地域或功能标志——逐步发布导致的曝光
突发后平静按时间段或
$current_url
——定时任务或特定页面

Picking the right version property

选择正确的版本属性

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?":
PropertyWhat it isAuto-captured byUse for
$exception_releases
Cymbal-managed release map, keyed by release IDOnly when SDK publishes release metadata (e.g. sourcemap upload tied to a release)Most precise release attribution when present
$app_version
The user's deployed app versioniOS (
CFBundleShortVersionString
), React Native (Expo / react-native-device-info)
"What deploy of my app introduced this?" — the question users care about
$lib_version
The PostHog SDK library version (e.g. posthog-js 1.298.0)Every SDK on every eventThe narrow "did upgrading the PostHog SDK introduce this?" question
$lib_version
is on virtually every event, which makes it tempting — but it's the PostHog library version, not the user's app version. A constant
$lib_version
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
$lib_version
only when nothing else is populated and you're explicitly asking "did upgrading PostHog cause this?".
Web / server / Node / Java / Python projects do not auto-capture
$app_version
— the customer has to set it (via
register
, a context provider, or
before_send
). If the breakdown comes back with one
$app_version
row of all-NULL, say so explicitly in the synthesis and suggest the customer wire it up; falling back to
$exception_releases
or to a per-day timeline by
first_seen
keeps the investigation moving.
Example (
$app_version
— populated automatically on mobile, manually on web / server):
sql
posthog:execute-sql
SELECT
    properties.$app_version AS app_version,
    count() AS occurrences,
    uniq(person_id) AS users,
    min(timestamp) AS first_seen,
    max(timestamp) AS last_seen
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 30 DAY
GROUP BY app_version
ORDER BY occurrences DESC
LIMIT 20
The
(issue_id = ... OR properties.$exception_issue_id = ...)
pattern mirrors the canonical
build_issue_where
clause from
products/error_tracking/backend/api/query_utils.py
.
issue_id
is the resolved virtual field on
events
(it follows fingerprint overrides so merged/split issues route correctly);
properties.$exception_issue_id
is the raw event property captured at ingestion. Filtering on only the property silently undercounts events for issues that have been merged or split.
If
first_seen
for one
app_version
is much later than the issue's overall
first_seen
, that release introduced or worsened the bug — strong root-cause signal. If every row is
NULL
, the SDK isn't reporting an app version on this project (common on web / server) — switch to
$exception_releases
if the customer ships releases, or fall back to a
toDate(timestamp)
timeline.
When
$exception_releases
is populated, it's a JSON dict keyed by release ID. There is no top-level
$release
property; query
$exception_releases
directly when you need release attribution and the customer has it wired up.
Repeat with
properties.$browser
,
properties.$os
,
properties.$current_url
, or any feature flag the project tags errors with.
PostHog会生成三个版本相关字段,它们的含义不同,只有一个能回答“用户应用的哪个版本引入了该错误?”:
属性说明自动捕获场景使用场景
$exception_releases
Cymbal管理的发布映射,以发布ID为键仅当SDK发布版本元数据时(例如与发布绑定的sourcemap上传)当存在时,是最精确的版本归因方式
$app_version
用户部署的应用版本iOS(
CFBundleShortVersionString
)、React Native(Expo / react-native-device-info)
回答“我的应用哪个部署版本引入了该错误?”——这是用户关心的核心问题
$lib_version
PostHog SDK库版本(例如posthog-js 1.298.0)所有SDK的所有事件都会自动捕获仅用于回答“升级PostHog SDK是否导致了该错误?”这一特定问题
$lib_version
几乎存在于所有事件中,容易被优先使用,但它是PostHog库的版本,而非用户应用的版本。如果
$lib_version
保持不变但错误激增,说明用户在未更改SDK的情况下发布了自身代码的回归版本,这是常见情况。仅当没有其他版本属性可用,且明确询问“升级PostHog是否导致该错误?”时,才使用
$lib_version
Web/服务器/Node/Java/Python项目不会自动捕获
$app_version
——客户需要手动设置(通过
register
、上下文提供者或
before_send
)。如果细分分析结果中
$app_version
行全为NULL,需在总结中明确说明,并建议客户配置该属性;此时可切换到
$exception_releases
(如果客户有发布版本),或按
first_seen
的每日时间线继续调查。
示例(
$app_version
——移动端自动捕获,Web/服务器需手动设置):
sql
posthog:execute-sql
SELECT
    properties.$app_version AS app_version,
    count() AS occurrences,
    uniq(person_id) AS users,
    min(timestamp) AS first_seen,
    max(timestamp) AS last_seen
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 30 DAY
GROUP BY app_version
ORDER BY occurrences DESC
LIMIT 20
(issue_id = ... OR properties.$exception_issue_id = ...)
模式与
products/error_tracking/backend/api/query_utils.py
中的标准
build_issue_where
子句一致。
issue_id
events
表上的解析虚拟字段(遵循指纹覆盖规则,确保合并/拆分的问题能正确路由);
properties.$exception_issue_id
是 ingestion 时捕获的原始事件属性。仅过滤该属性会导致合并或拆分的问题事件被遗漏统计。
如果某个
app_version
first_seen
远晚于问题整体的
first_seen
,说明该版本引入或加剧了bug——这是强根因信号。如果所有行都是NULL,说明该项目的SDK未上报应用版本(Web/服务器端常见)——若客户有发布版本,切换到
$exception_releases
,否则退回到按
toDate(timestamp)
的时间线分析。
$exception_releases
已配置时,它是一个以发布ID为键的JSON字典。没有顶级的
$release
属性;当需要版本归因且客户已配置时,直接查询
$exception_releases
可重复以上操作,使用
properties.$browser
properties.$os
properties.$current_url
或项目标记错误时使用的任何功能标志作为维度。

Step 4 — Check feature flag exposure

步骤4 — 检查功能标志曝光情况

If the user suspects an experiment or rollout, check whether affected users had a flag enabled when the error fired.
To enumerate which flags were evaluated on affected users, parse the
$active_feature_flags
property — it is materialized as a JSON-encoded string in ClickHouse, so
arrayJoin(properties.$active_feature_flags)
directly will fail;
JSONExtract
is the working pattern:
sql
posthog:execute-sql
SELECT
    arrayJoin(JSONExtract(toString(properties.$active_feature_flags), 'Array(String)')) AS flag,
    count() AS occurrences,
    uniq(person_id) AS users
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 14 DAY
    AND notEmpty(toString(properties.$active_feature_flags))
GROUP BY flag
ORDER BY occurrences DESC
LIMIT 20
Caveat: every event captures every evaluated flag key, so this enumeration often returns identical counts across flags and doesn't tell you which flag correlates with the error — only which were on the user. To actually test a hypothesis, query the per-flag value column
properties.$feature/<flag-key>
, which carries the evaluated value (
true
/
false
/variant name):
sql
posthog:execute-sql
SELECT
    properties.`$feature/my-flag-key` AS variant,
    count() AS occurrences,
    uniq(person_id) AS users
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 14 DAY
GROUP BY variant
ORDER BY occurrences DESC
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.
如果用户怀疑实验或版本发布导致错误,检查受影响用户在错误发生时是否启用了相关标志。
要枚举受影响用户评估过的标志,需解析
$active_feature_flags
属性——它在ClickHouse中以JSON编码字符串形式存储,因此直接使用
arrayJoin(properties.$active_feature_flags)
会失败;正确的方式是使用
JSONExtract
sql
posthog:execute-sql
SELECT
    arrayJoin(JSONExtract(toString(properties.$active_feature_flags), 'Array(String)')) AS flag,
    count() AS occurrences,
    uniq(person_id) AS users
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 14 DAY
    AND notEmpty(toString(properties.$active_feature_flags))
GROUP BY flag
ORDER BY occurrences DESC
LIMIT 20
注意:每个事件都会捕获所有评估过的标志键,因此该枚举通常会返回各标志的相同计数,无法告知哪个标志与错误相关——仅能知道哪些标志在用户端启用。要验证假设,需查询每个标志的取值列
properties.$feature/<flag-key>
,该列存储评估后的值(
true
/
false
/变体名称):
sql
posthog:execute-sql
SELECT
    properties.`$feature/my-flag-key` AS variant,
    count() AS occurrences,
    uniq(person_id) AS users
FROM events
WHERE event = '$exception'
    AND (issue_id = '<issue_id>' OR properties.$exception_issue_id = '<issue_id>')
    AND timestamp > now() - INTERVAL 14 DAY
GROUP BY variant
ORDER BY occurrences DESC
将此处的变体分布与同一时间段内项目中该标志的整体曝光情况进行对比。如果某个变体的占比过高,说明该标志可能与错误原因相关——虽非绝对,但属于强假设。

Step 5 — Reconstruct what happened around the error

步骤5 — 重建错误发生前后的场景

Use the
$session_id
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.
使用步骤2中样本事件的
$session_id
,获取异常发生前后的活动数据。有三个数据源可供使用,根据捕获错误的SDK选择合适的数据源运行。

5a. Surrounding events (client SDKs by
$session_id
)

5a. 关联事件(客户端SDK按
$session_id

Mirrors the ET frontend session timeline. Pulls custom events, page views, and other exceptions captured under the same session within a ±1h window:
sql
posthog:execute-sql
SELECT
    uuid,
    event,
    timestamp,
    properties.$lib AS lib,
    properties.$current_url AS url
FROM events
WHERE $session_id = '<session_id_from_step_2>'
    AND (event = '$exception' OR event = '$pageview' OR left(event, 1) != '$')
    AND timestamp >= toDateTime('<error_timestamp>', 'UTC') - INTERVAL 1 HOUR
    AND timestamp <= toDateTime('<error_timestamp>', 'UTC') + INTERVAL 1 HOUR
ORDER BY timestamp ASC
LIMIT 100
The
left(event, 1) != '$'
clause drops PostHog autocapture / system events while keeping every custom event. The
OR event = '$pageview'
/
'$exception'
exceptions re-add the two system events worth seeing on the timeline. This is the same filter the ET UI uses.
Mixed
$lib
values in the output are a feature, not noise. When a server SDK propagates
$session_id
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.
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.
镜像ET前端会话时间线,获取同一会话中±1小时窗口内的自定义事件、页面浏览和其他异常:
sql
posthog:execute-sql
SELECT
    uuid,
    event,
    timestamp,
    properties.$lib AS lib,
    properties.$current_url AS url
FROM events
WHERE $session_id = '<session_id_from_step_2>'
    AND (event = '$exception' OR event = '$pageview' OR left(event, 1) != '$')
    AND timestamp >= toDateTime('<error_timestamp>', 'UTC') - INTERVAL 1 HOUR
    AND timestamp <= toDateTime('<error_timestamp>', 'UTC') + INTERVAL 1 HOUR
ORDER BY timestamp ASC
LIMIT 100
left(event, 1) != '$'
子句会过滤PostHog自动捕获/系统事件,保留所有自定义事件。
OR event = '$pageview'
/
'$exception'
例外会重新添加时间线中值得关注的两个系统事件。这与ET UI使用的过滤规则一致。
输出中出现混合的
$lib
值是正常功能,而非噪声。当服务器SDK从客户端请求中传播
$session_id
时(PostHog自身后端会这么做),时间线会将服务器端活动与浏览器端活动合并显示——免费实现“同时展示两端SDK数据”。查看lib列即可了解每行数据的来源。
该流程默认使用±1小时窗口,与UI保持一致;当问题相关操作耗时较长(如批量处理任务、后台工作线程)时可扩大窗口,当仅需关注错误发生前几秒的活动时可缩小窗口。

5b. Console logs (web / React Native session replay)

5b. 控制台日志(Web/React Native会话重放)

When session replay is enabled, the replay pipeline emits
console.*
calls into the
log_entries
table tagged with the same session id. Pull them with the matching window:
sql
posthog:execute-sql
SELECT timestamp, level, message
FROM log_entries
WHERE log_source = 'session_replay'
    AND log_source_id = '<session_id_from_step_2>'
    AND timestamp >= toDateTime('<error_timestamp>', 'UTC') - INTERVAL 1 HOUR
    AND timestamp <= toDateTime('<error_timestamp>', 'UTC') + INTERVAL 1 HOUR
ORDER BY timestamp ASC
LIMIT 200
log_source = 'session_replay'
is the discriminator —
log_entries
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.
当会话重放启用时,重放流水线会将
console.*
调用发送到
log_entries
表,并标记相同的会话ID。在匹配的窗口内获取这些日志:
sql
posthog:execute-sql
SELECT timestamp, level, message
FROM log_entries
WHERE log_source = 'session_replay'
    AND log_source_id = '<session_id_from_step_2>'
    AND timestamp >= toDateTime('<error_timestamp>', 'UTC') - INTERVAL 1 HOUR
    AND timestamp <= toDateTime('<error_timestamp>', 'UTC') + INTERVAL 1 HOUR
ORDER BY timestamp ASC
LIMIT 200
log_source = 'session_replay'
是区分符——
log_entries
表与其他数据源共享。空结果很常见:要么未启用会话重放,要么该特定会话未被录制。需在总结中提及这一点,而非视为失败。

5c. Server logs around the error (OTEL via
query-logs
)

5c. 错误发生前后的服务器日志(通过
query-logs
获取OTEL日志)

For server-side exceptions, correlate the exception timestamp with OTEL log entries the customer ingests. Many projects don't ingest logs at all — if
query-logs
returns nothing or errors, say so and move on. Discover available services first with
logs-attribute-values-list
when you don't know which service produced the error.
json
posthog:query-logs
{
  "query": {
    "dateRange": {
      "date_from": "<error_timestamp minus 5 minutes>",
      "date_to":   "<error_timestamp plus 5 minutes>"
    },
    "severityLevels": ["error", "warn"],
    "serviceNames": ["<service.name if known>"],
    "limit": 50,
    "orderBy": "earliest"
  }
}
Caveats worth knowing before relying on this output:
  • Logs are ingested separately from events and typically have shorter retention. Old exceptions may return empty even though the issue is still active.
  • trace_id
    /
    span_id
    come back zero-padded (
    "00000000..."
    ) when not set. Trace-based correlation only works for explicitly instrumented requests, not for every event.
  • service.name
    is a resource attribute. Narrow with
    serviceNames
    rather than a free-text
    searchTerm
    when you know the producer.
对于服务器端异常,将异常时间与客户摄入的OTEL日志条目关联。许多项目根本不摄入日志——如果
query-logs
返回空或报错,说明情况并继续调查。当不知道哪个服务产生错误时,先使用
logs-attribute-values-list
发现可用服务。
json
posthog:query-logs
{
  "query": {
    "dateRange": {
      "date_from": "<error_timestamp minus 5 minutes>",
      "date_to":   "<error_timestamp plus 5 minutes>"
    },
    "severityLevels": ["error", "warn"],
    "serviceNames": ["<service.name if known>"],
    "limit": 50,
    "orderBy": "earliest"
  }
}
在依赖此输出前,需注意以下限制:
  • 日志与事件分开摄入,通常保留时间更短。即使问题仍活跃,旧异常可能返回空结果。
  • 当未设置时,
    trace_id
    /
    span_id
    会返回零填充值(
    "00000000..."
    )。基于追踪的关联仅适用于显式 instrumentation 的请求,而非所有事件。
  • service.name
    是资源属性。当知道生产者时,使用
    serviceNames
    缩小范围,而非自由文本
    searchTerm

5d. Find a representative replay

5d. 找到具有代表性的会话重放

Hand off to
finding-replay-for-issue
when picking the best 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.
Skip the hand-off and pull a recording inline via
query-session-recordings-list
with
session_ids
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).
If neither path returns a recording, mention that session replay may not be enabled for the affected users — useful context, not a failure.
当需要选择最佳会话时,交给
finding-replay-for-issue
处理——热门问题会关联数百个录制,其中大多是短崩溃片段或闲置标签会话,该技能会应用时长/活跃时间/时效性排序,找到最可能展示原因的会话。当用户仅要求“一个重放”而未指定具体会话时,也可交给该技能处理。
当仅关联了少量会话、用户已指定特定会话,或任何可用示例即可(例如证明错误可复现)时,可跳过转交,直接使用步骤2中已获取的样本异常事件的
session_ids
,通过
query-session-recordings-list
内联获取录制。
如果两种方式都未返回录制,需提及受影响用户可能未启用会话重放——这是有用的上下文,而非失败。

Step 6 — Synthesize

步骤6 — 生成总结

Present in this order:
  1. What it is — type, message, where in the stack
  2. Who it affects — total users, sessions, and any segment breakdown that stood out
  3. When it started
    first_seen
    , plus the release / version that introduced it if a breakdown found one
  4. Likely cause — one or two hypotheses backed by the breakdowns above
  5. Next step — a concrete action: investigate the suspected release, watch the linked replay, ping the assignee, or escalate
Keep the synthesis tight. The user wants the answer, not a tour of the data.
按以下顺序呈现:
  1. 错误概况——类型、消息、调用栈位置
  2. 影响范围——总用户数、会话数,以及任何突出的细分维度数据
  3. 起始时间——
    first_seen
    ,如果细分分析找到相关版本/发布,需说明引入错误的版本
  4. 可能原因——基于上述细分分析的1-2个假设
  5. 后续步骤——具体行动:调查疑似版本、查看关联重放、联系负责人或升级问题
总结需简洁。用户需要的是答案,而非数据展示。

Tips

提示

  • The canonical join key from events to an issue is the resolved
    issue_id
    virtual field, with
    properties.$exception_issue_id
    as fallback — see Step 3 for the reason and the
    build_issue_where
    pattern.
  • For a "what version introduced this?" breakdown, prefer
    $app_version
    (the user's deployed app version, auto-captured on iOS / React Native and manually set on web / server) or
    $exception_releases
    when populated. Avoid
    $lib_version
    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.
  • If the issue spans more than 30 days, widen the date range explicitly. Defaults often truncate the original
    first_seen
    event off the breakdown.
  • 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.
  • If
    query-error-tracking-issue
    returns an
    external_issues
    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.
  • 从事件到问题的标准关联键是解析后的
    issue_id
    虚拟字段,
    properties.$exception_issue_id
    作为备选——原因和
    build_issue_where
    模式见步骤3。
  • 对于“哪个版本引入了该错误?”的细分分析,优先使用
    $app_version
    (用户部署的应用版本,iOS/React Native自动捕获,Web/服务器需手动设置)或已配置的
    $exception_releases
    。避免使用
    $lib_version
    回答此问题——它是PostHog SDK库版本,而非用户应用版本。详见步骤3中的“选择正确的版本属性”小节。
  • 如果问题持续超过30天,需显式扩大日期范围。默认设置可能会截断原始的
    first_seen
    事件,导致细分分析不完整。
  • 除非从样本调用栈中能明显看出原因,否则不要在总结中提出修复方案。基于数据的假设比主观猜测更有用。
  • 如果
    query-error-tracking-issue
    返回
    external_issues
    数组,说明该问题已关联到Linear/Jira/GitHub工单。需在总结中提及该链接,避免用户重复创建工单。