Automatic grouping

One bug, one issue, no matter how many times it happens

Every exception is fingerprinted from its class, message, and backtrace, so the same bug reported a thousand times shows up as one issue, not a thousand.

How the fingerprint is actually built

Grouping runs entirely in a background job, never in the ingestion request itself, so a burst of traffic never makes the client wait on it. The fingerprint is a SHA-256 hash of the exception class, a normalized version of the message, and a normalized version of the backtrace, and normalization is deliberately simple rather than a full templating engine: good enough to group the common cases without pretending to solve every one.

In-app backtrace frames (the ones your own client tags as yours, not a gem's or the framework's) are preferred over framework frames for grouping, since your own code is what actually changes between two occurrences of the same logical bug. Line numbers are dropped entirely, since they shift on every unrelated refactor, and gem version segments are stripped out of file paths, so bumping a gem doesn't fragment an issue that hasn't actually changed.

The message itself gets normalized too: hex object ids, UUIDs, and bare numeric ids are all replaced with placeholders before hashing, since those are unique per occurrence, not per bug. "Couldn't find Invoice with id=8821" and "Couldn't find Invoice with id=9004" hash identically. Grouping is capped to the first 10 in-app frames, both to keep very deep stacks stable and to keep hashing cheap at ingestion volume.

An issue list, showing one row per grouped issue with its event count and last-seen time

Every issue is one row, however many times it's actually happened.


Regressions

Mark an issue resolved and it stays that way until the exact same fingerprint is reported again. When that happens, it flips itself back to unresolved and stamps a regressed_at timestamp, with no fresh report needed from anyone to notice: the next occurrence does it automatically, the moment it's grouped.

This only applies to a resolved issue. An ignored issue reported again stays ignored; ignoring is a "stop telling me about this specific fingerprint" decision, not a temporary snooze, so it doesn't get treated as a regression the way resolving does.

An issue's detail page in ForgeOps, showing its status, assignment, and backtrace

Each occurrence keeps its own timestamp, environment, and backtrace, grouped under one issue.


Safe under concurrent load

A brand-new fingerprint reported by a sudden burst of concurrent requests doesn't create duplicate issues. Grouping relies on a unique database index across project and fingerprint, not an application-level check-then-create: if two workers both try to insert the same new fingerprint at once, the database itself rejects the second insert, and that worker retries into the update path instead, landing on the exact same issue the first worker created.


Team discussion, right on the issue

Every issue has its own comment thread, right below its occurrences: leave a note for whoever picks it up next ("same timeout as last week, checking the payment gateway's status page now"), without opening Slack or a separate ticket just to say so.

A viewer can read the thread but not add to it; anyone else on the team can, and can always take back their own comment. Beyond that, only an admin or owner can remove someone else's, the same tier that already manages the rest of an organization's membership.

An issue's Discussion thread, showing two teammates trading notes about the same underlying error

A running record of who looked at what, without leaving the issue itself.


When two issues turn out to be one bug

Fingerprinting groups the common case, but not every case: a refactor can shift an exception's message or backtrace just enough that the same underlying bug gets fingerprinted differently before and after, showing up as two separate issues. Merge one into the other by hand from either issue's own page, and every event either one has ever recorded moves onto the survivor, combining their history into one row instead of two.

The merged-away issue's own page and comment thread both stay reachable, not deleted, just marked as folded into another issue; visiting its old link forwards straight to the survivor. From that point on, any further occurrence of the merged-away issue's own fingerprint is recorded against the survivor too, so the same bug never splits itself back into two issues the next time it happens.

An issue's Merge into control, showing a dropdown of other open issues in the project

When grouping doesn't catch it automatically, a couple of clicks combines the two by hand.


See it on your own data

Free plan included, no credit card required. New organizations start with 14 days of Business.

Get started free