Skip to content

Let apps shape the fingerprint, so a message with a per-request id doesn't split one error into many #116

Open

Description

@namolnad

An error's fingerprint is a hash of its class, message, severity and source. When a message embeds something that changes with every occurrence, such as a request id, a record id or a timestamp, each occurrence becomes an error of its own. The dashboard fills with near-identical errors that each have one occurrence. That hides a real outage, which looks like hundreds of new errors rather than one error with hundreds of occurrences, and since every one is "new", each one is emailed.

The case we hit is API client errors that end with the provider's request id:

Anthropic::Errors::InternalServerError: Internal server error (request_id: req_011CT8...)

What we do today is wrap the subscriber. We unsubscribe SolidErrors::Subscriber and subscribe one that rewrites the exception's message, replacing req_... with a placeholder and moving the id into the context, before handing it on. It works, but it means replacing the gem's subscriber and redefining #message on the exception.

A possible shape: an optional hook that turns the attributes into the fingerprint, defaulting to what happens now:

config.solid_errors.fingerprint = ->(error:, attributes:) {
  message = attributes[:message].gsub(/\breq_[A-Za-z0-9]+/, "req_*")
  [attributes[:exception_class], message, attributes[:severity], attributes[:source]].join
}

The stored message would stay as reported, so the id is still there to quote, and only the grouping would change. A narrower alternative is a message-normalizing proc that applies only to the fingerprint.

Would something like this be welcome? If so, I can send a small PR: the config option, the call in Subscriber#report, a README section and tests.

Activity

  1. fractaledmind commented on Oct 19, 2026

    @fractaledmind
    Owner

    Yes, this would be welcome, and the request-id case is a good motivating example. Please send the PR.

    The shape you sketched works for me: a fingerprint proc that receives the error and its attributes, defaults to today's hash of class, message, severity and source, and leaves the stored message as reported. A few things to keep in it:

    • Existing errors keep their fingerprints unless an app sets the proc, so upgrading never regroups anyone's data.
    • A test that two messages differing only in the id group into one error, and that the stored messages keep their ids.
    • A README section next to ignored_errors.

    Thanks for the triage repo link too, I'll have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions