Skip to content
Console
Menu

Queues

Workflows

Getting Started

Authentication

KV Store

Errors

Grouping, capture, and the three calls that move a group through triage

An error arrives as an occurrence and is read as a group. The occurrence is never changed once stored; what moves is the group, and only through the calls on this page. The error_groups collection has every method, its scope and its examples.

#How a group is chosen

An Error Group is the deterministic grouping of error occurrences by fingerprint. A capture is grouped by fingerprint when the caller sets one, and otherwise by exception type and the symbolicated in-app stack.

Release is never part of the group key. last_release reports the release of the latest occurrence, and nothing else, which is why one bug stays one group across releases rather than starting again at every deploy.

Everything a group reports is derived from its occurrences:

FieldTypeWhat it is
fingerprintstringThe grouping fingerprint. Output only.
titlestringThe exception type and message of the first occurrence. Output only.
culpritstringThe top in-app frame. Output only.
service_namestringThe emitting service. Output only.
stateErrorGroupStateThe triage state: unresolved, acknowledged or resolved. Output only.
first_seen_timetimestampThe first occurrence. Output only.
last_seen_timetimestampThe latest occurrence. Output only.
occurrence_countint64Occurrences, all time. Output only.
last_releasestringThe release of the latest occurrence. Output only.

#Capture an occurrence

capture takes one occurrence. event_time and exception_type are required; everything else sharpens the group or the record.

FieldTypeWhat it is
event_timetimestampWhen it happened. Required.
exception_typestringThe exception type. Required.
messagestringThe exception message.
stackstringThe stack as the runtime printed it. Scrubbed before storage.
stack_framesStackFrame[]Stack frames, innermost last. When set, it wins and stack is kept as sent.
service_namestringThe emitting service.
releasestringThe release the emitter ran. It selects the source maps the frames are mapped through.
breadcrumbsBreadcrumb[]Breadcrumbs before the error, oldest first.
tagsmap<string, string>Typed tags.
fingerprintstringOverrides the grouping fingerprint.
trace_idstringW3C trace id (32 hex), which connects the occurrence to a trace.
span_idstringW3C span id (16 hex).
Shell
sylphx observability error-groups capture orgs/acme/projects/shop/envs/production
Shell
curl -X POST "https://api.sylphx.com/v1/orgs/acme/projects/shop/envs/production/error_groups:capture" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"error_event":{"event_time":{},"exception_type":"…"}}'
TypeScript
const response = await sylphx.observability.errorGroups.capture({ errorEvent: { eventTime: {}, exceptionType: '…' }, parent: 'orgs/acme/projects/shop/envs/production' })

The stack is read for you

When stack_frames is empty, V8 lines (at fn (file:line:col)) and Gecko/WebKit lines (fn@file:line:col) are parsed into frames, innermost last. When stack_frames is set, it wins and stack is kept as sent. Either way the frames are mapped through the source maps uploaded for release before the group is chosen — Source maps is the upload.

Secrets and personal data are scrubbed by the environment's Scrubbing Policy before the occurrence is stored, and stack is scrubbed with the rest.

#Read a group and its occurrences

An Error Event is one immutable error occurrence, with breadcrumbs and correlation, and it lives under the group it joined. Nothing rewrites an occurrence, so a group's history cannot be edited — only its state moves.

Shell
sylphx observability error-groups list orgs/acme/projects/shop/envs/production
sylphx observability error-groups get orgs/acme/projects/shop/envs/production/error_groups/error-group
sylphx observability error-events list orgs/acme/projects/shop/envs/production/error_groups/error-group
sylphx observability error-events get orgs/acme/projects/shop/envs/production/error_groups/error-group/error_events/error-event

Listing groups filters by state, service_name and last_seen_time, which is how a triage list is built: the groups still unresolved, for one service, seen in the interval you care about.

An occurrence carries what the capture sent — its breadcrumbs oldest first, its tags, its release — and the trace_id and span_id that connect it to a trace. Together those are the difference between knowing a group fired and knowing what the request was doing when it did.

#Triage a group

Acknowledge, resolve and reopen require the current etag: read the group, and send the etag you read back with the call. A call whose etag no longer matches fails with ETAG_MISMATCH and changes nothing, which is what stops two people triaging the same group from overwriting each other.

Shell
sylphx observability error-groups acknowledge orgs/acme/projects/shop/envs/production/error_groups/error-group --etag …
Shell
curl -X POST "https://api.sylphx.com/v1/orgs/acme/projects/shop/envs/production/error_groups/error-group:acknowledge" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript
const response = await sylphx.observability.errorGroups.acknowledge({ name: 'orgs/acme/projects/shop/envs/production/error_groups/error-group' })

acknowledge says the group is seen and being worked on. resolve says it is done — and a new occurrence reopens it, so a resolve is a statement about now rather than a promise about later:

Shell
sylphx observability error-groups resolve orgs/acme/projects/shop/envs/production/error_groups/error-group --etag …
Shell
curl -X POST "https://api.sylphx.com/v1/orgs/acme/projects/shop/envs/production/error_groups/error-group:resolve" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript
const response = await sylphx.observability.errorGroups.resolve({ name: 'orgs/acme/projects/shop/envs/production/error_groups/error-group' })

reopen takes a resolved or an acknowledged group back to triage, which is the call to reach for when the bug was not fixed after all:

Shell
sylphx observability error-groups reopen orgs/acme/projects/shop/envs/production/error_groups/error-group --etag …
Shell
curl -X POST "https://api.sylphx.com/v1/orgs/acme/projects/shop/envs/production/error_groups/error-group:reopen" \
  -H "Authorization: Bearer $SYLPHX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
TypeScript
const response = await sylphx.observability.errorGroups.reopen({ name: 'orgs/acme/projects/shop/envs/production/error_groups/error-group' })

A call the group's state forbids — reopening one that is already unresolved — fails with INVALID_STATE. The error_groups commands show the --etag flag on each of the three.