Skip to main content

Error Grouping

Monitoring

Learn how errors are automatically grouped and how to customize fingerprinting for better error management.

Default Fingerprinting

Automatic grouping by error type and stack trace

Custom Fingerprints

Define your own grouping logic

Smart Deduplication

Similar errors grouped together

Merge & Split

Manually adjust error groups

How Errors Are Grouped

When an error is captured, Sylphx generates a fingerprint to group it with similar errors. This prevents your dashboard from being flooded with duplicate entries and helps you understand the true impact of each unique error.

Errors with the same fingerprint are grouped into a single issue, showing:

  • Total occurrence count
  • Unique users affected
  • First and last seen timestamps
  • Trend over time
  • All individual events for investigation

Default Fingerprinting Algorithm

By default, Sylphx creates fingerprints using a combination of:

Error Type

The exception class (TypeError, ReferenceError, etc.)

Error Message

Normalized message with variables removed

Stack Trace

Top frames of the call stack (file, function, line)

Source Location

The file and function where the error originated

Example: Same Fingerprint
// These two errors will be grouped together:

// Error 1
TypeError: Cannot read property 'name' of undefined
  at getUser (src/api/users.ts:42)
  at handleRequest (src/server.ts:15)

// Error 2
TypeError: Cannot read property 'name' of undefined
  at getUser (src/api/users.ts:42)
  at handleRequest (src/server.ts:15)

// Same error type, message, and stack trace = same fingerprint

Message Normalization

Error messages are normalized before fingerprinting. Dynamic values like IDs, timestamps, and URLs are replaced with placeholders so similar errors group together regardless of specific values.
Message Normalization Examples
// These messages are normalized to the same pattern:

"User 12345 not found"     -> "User {id} not found"
"User 67890 not found"     -> "User {id} not found"

"Request timeout after 30s" -> "Request timeout after {n}s"
"Request timeout after 60s" -> "Request timeout after {n}s"

"Failed to fetch https://api.example.com/users/123"
-> "Failed to fetch {url}"

Custom Fingerprints

For more control over grouping, you can provide a custom fingerprint when capturing errors. This is useful when:

  • The default grouping is too broad or too narrow
  • You want to group errors by business logic (e.g., payment provider)
  • Different stack traces should be grouped together
  • The same stack trace should be split into different groups
Server-side
import { platform } from '@/lib/platform'

// Group all payment failures by provider
try {
  await processPayment(provider, amount)
} catch (error) {
  await platform.monitoring.captureException({
    error,
    fingerprint: ['payment-failure', provider],
    // Creates groups like:
    // - payment-failure-stripe
    // - payment-failure-paypal
    // - payment-failure-braintree
  })
}
// Group all checkout errors together regardless of stack trace
await platform.monitoring.captureException({
  error,
  fingerprint: ['checkout-flow', checkoutStep],
  context: {
    step: checkoutStep,
    cartValue: cart.total,
  },
})

// Results in groups:
// - checkout-flow-cart
// - checkout-flow-shipping
// - checkout-flow-payment
// - checkout-flow-confirmation

Using {{ default }}

The special value {{ default }} includes the auto-generated fingerprint. This lets you add custom dimensions while preserving the default grouping behavior.

Grouping by Error Type vs Message

Sometimes you want errors grouped purely by type (ignoring the message), or purely by message (ignoring the type). Here's how to achieve both:

// Group all TypeErrors together, regardless of message
await platform.monitoring.captureException({
  error,
  fingerprint: [error.name], // Just the error type
})

// All of these become one group:
// - TypeError: Cannot read property 'x' of undefined
// - TypeError: Cannot read property 'y' of null
// - TypeError: x is not a function

Handling Similar But Distinct Errors

Sometimes errors look similar but have different root causes. Here's how to keep them separate:

Distinguishing Similar Errors
// These look the same but have different causes:
// 1. Network timeout to API
// 2. Network timeout to CDN
// 3. Network timeout to database

try {
  await fetchWithTimeout(url, { timeout: 5000 })
} catch (error) {
  if (error.name === 'TimeoutError') {
    // Parse the URL to determine the service
    const service = categorizeUrl(url) // 'api' | 'cdn' | 'database'

    await platform.monitoring.captureException({
      error,
      fingerprint: ['timeout', service],
      context: {
        url,
        service,
        timeout: 5000,
      },
    })
  }
}

function categorizeUrl(url: string): string {
  if (url.includes('api.')) return 'api'
  if (url.includes('cdn.')) return 'cdn'
  if (url.includes('db.') || url.includes(':5432')) return 'database'
  return 'other'
}

Avoid Over-Grouping

Be careful not to create fingerprints that are too broad. Grouping unrelated errors together makes it harder to identify and fix individual issues.

Merging and Splitting Groups

From the Sylphx dashboard, you can manually merge or split error groups when the automatic fingerprinting doesn't match your needs.

Merging Groups

Merge groups when you discover that separate issues are actually the same root cause:

1
Select multiple issues from the issue list
2
Click "Merge Issues" in the actions menu
3
Choose which issue to keep as the primary
4
All events are consolidated into the primary issue
5
Future matching errors go to the merged group

Splitting Groups

Split a group when it contains errors that should be tracked separately:

1
Open the issue detail page
2
Click "Split Issue" in the actions menu
3
Select events to move to a new issue
4
Optionally set a custom fingerprint rule
5
A new issue is created with the selected events

Fingerprint Rules

When splitting issues, you can create a fingerprint rule that automatically routes future matching errors to the correct group.

Fingerprint Rules

Create persistent rules to automatically group errors without code changes:

Dashboard Fingerprint Rule
// Example rule configuration in the dashboard:

{
  "name": "Payment provider errors",
  "conditions": [
    { "field": "error.message", "contains": "payment" }
  ],
  "fingerprint": [
    "payment-error",
    "{{ tags.provider }}"
  ],
  "priority": 100  // Higher priority rules are evaluated first
}

// This rule will:
// 1. Match any error with "payment" in the message
// 2. Group by the provider tag
// 3. Override the default fingerprint
PropertyTypeDescription
namerequiredstringHuman-readable name for the rule
conditionsrequiredCondition[]Conditions that must match for the rule to apply
fingerprintrequiredstring[]The fingerprint to use when conditions match
prioritynumber= 0Rule evaluation order (higher = first)
enabledboolean= trueWhether the rule is active

Best Practices

Start with defaults

The default fingerprinting works well for most cases. Only customize when you see grouping issues.

Use meaningful fingerprints

Choose fingerprint values that are stable and meaningful, like feature names or error categories.

Include context

Even with custom fingerprints, include rich context in your error reports for debugging.

Review periodically

Check your error groups regularly to ensure similar issues are grouped appropriately.