Error grouping and fingerprinting, explained
Grouping is the invisible feature of an error tracker: when it works you never think about it, and when it fails you drown in duplicate issues or — worse — miss a real bug hiding inside an unrelated one. Here's how Sentry-style fingerprinting actually decides that two events are 'the same', and how to take control when the defaults get it wrong.
The problem: same bug, different-looking events
Two occurrences of the same bug rarely produce byte-identical events. Line numbers shift between releases. Async boundaries reshuffle stack frames. Messages embed user ids, timestamps and URLs. A naive equality check would open a new issue for nearly every event; grouping exists to see through the noise.
How exception fingerprinting works
For events with a stack trace, the fingerprint is built from the exception type plus a normalized signature of the in-app frames:
- Frames from libraries and the runtime are dropped when in-app frames exist — your code is the stable part.
- Filenames are reduced to their basename and function names are stripped of namespaces (
Object.handler→handler). - Absolute line/column numbers are ignored — they churn with every deploy.
- Consecutive identical frames collapse, so a recursive crash at depth 3 groups with the same crash at depth 3,000.
- Chained exceptions (
caused by) are folded in, so a wrapper error with a different root cause becomes a different issue.
Message events: parameterization
Events without a stack trace group by their message — after the volatile tokens are replaced with placeholders. Payment failed for order #48213 (took 3.2s) becomes Payment failed for order #<int> (took <float>s), so every occurrence lands in one issue. Good parameterizers handle ints, floats, UUIDs, hashes, emails, URLs, IPs and dates.
When defaults fail: custom fingerprints
Two classic failure modes: over-grouping (a generic TimeoutError from your HTTP client groups together for every downstream API) and over-splitting (a minified frontend without source maps produces different mangled frames per build). Both are fixed with explicit fingerprints in the SDK:
Sentry.captureException(err, {
fingerprint: ['api-timeout', targetService],
});Server-side grouping rules
SDK fingerprints require a deploy. Server-side rules don't: a pattern like type:TimeoutError message:*payments* → fingerprint payments-timeout regroups matching events from the moment you save it. jentry supports both, mirroring Sentry's semantics, so your existing mental model (and your existing custom fingerprints) carry over unchanged.
Practical grouping hygiene
- 1Upload source maps (or ship server-side symbols) — grouping quality on minified code is grouping quality on garbage otherwise.
- 2Keep exception messages human-readable and put variable data in tags/extra, not in the message.
- 3Review your top 10 issues monthly: if one issue is clearly two bugs, split it with a fingerprint rule.
- 4Treat 'ignore' as a grouping tool — an issue you'll never fix should stop generating noise.
Frequently asked questions
Why did one bug create hundreds of issues?
Usually missing source maps (each release produces different minified frames) or dynamic data defeating message parameterization. Fix the maps first; add a custom fingerprint if the events still split.
Why did two different bugs group into one issue?
They likely share their in-app stack signature — common with generic wrappers (HTTP clients, ORMs). Add a custom fingerprint that includes the distinguishing dimension, like the downstream service name.
Do custom fingerprints from Sentry SDKs work with jentry?
Yes. jentry reads the same fingerprint field the Sentry SDKs send and applies the same override semantics, so existing code keeps working when you point the DSN at jentry.
Does changing grouping rules re-group old events?
Like in Sentry, rules apply to events from the moment they exist — history stays where it was. Plan grouping changes when a noisy issue is active, not after it quiets down.
Try jentry free
Hosted error tracking & performance monitoring. Works with your Sentry SDKs — send your first event in minutes.