Issues
Issues capture problems in your application — exceptions, panics, and explicitly sent messages.
What Creates an Issue
An issue is created when:
- A panic or unhandled exception occurs during a traced request or task
- An error is reported to the client SDK during request handling
- Your code explicitly captures an exception or message through the client SDK
Errors vs Messages
Traceway captures two kinds of issues:
- Errors — Runtime exceptions with stack traces (panics, captured errors)
- Messages — Explicitly captured strings sent through the client SDK
Both appear in the Issues list with full context and attributes.
Connection to Traces
Issues can be linked to a trace via context. When an exception occurs during an HTTP request or background task, the trace ID is automatically attached to the issue.
This linkage means:
- Viewing an issue shows which endpoint or task triggered it
- Viewing a trace shows any issues that occurred during execution
- Attributes from the trace context are included in the issue
Issues captured outside of a trace context (no active request or task) are recorded as standalone issues without a trace link.
Fingerprinting
Every error is assigned a fingerprint: a 16-character hash of its normalized stack trace. The fingerprint is the identity of an issue. All occurrences that share it fold into a single issue, the issue URL contains it (/issues/<hash>), and archiving, regression detection, and alerting all key on it.
Why Group Errors
Without grouping, one bug in a hot path produces thousands of raw exceptions that differ only in runtime data: another user ID, another memory address, another server. Grouping reduces that stream to one issue with an occurrence count, which keeps two things useful:
- The issues list stays readable. One row per root cause instead of pages of near-duplicates, so the list ranks real problems rather than repetitions of the same one.
- Alerts stay consistent. A New Issue rule fires once per group, not once per occurrence, and Error Regression can tell that a previously resolved error has genuinely returned. If grouping were unstable, every alert rule would either flood you or stay silent.
How the Hash Is Computed
Before hashing, Traceway normalizes the stack trace so values that vary between occurrences of the same bug never affect the hash:
| Normalization | Effect |
|---|---|
| Error message | Only the error type is kept (TimeoutError, *net.OpError). The message text, which often embeds user data, is dropped, including the messages on JVM Caused by: lines. |
| Runtime values | Hex addresses, UUIDs, IP addresses and ports, email addresses, goroutine numbers, and long numbers (epoch timestamps, numeric IDs) are replaced with placeholders. |
| File locations | Absolute paths collapse to filename:line, URL origins are stripped from browser frames, and @v1.2.3 module version suffixes are removed so a dependency bump does not split a group. |
| JVM frames | Line numbers inside (File.java:123) are dropped, and ... 12 more becomes ... more. |
| Column numbers | Dropped everywhere except line 1, where they are kept: minified bundles put everything on line 1, and the column is the only thing distinguishing frames there. |
| Resolved function names | Function names produced by the symbolicator are excluded from the hash, so uploading source maps later improves readability without reshuffling existing groups. |
| Whitespace | Runs of spaces and blank lines are collapsed. |
The normalized trace is hashed with SHA-256 and truncated to 16 characters.
What Stays Together, What Splits
The same logical error keeps the same hash across servers, environments, app versions, and users. A new hash (and therefore a new issue and a New Issue alert) appears when the failure itself changes: a different error type, or a different code path with different frames. Line numbers are part of the hash, so a refactor that moves code within a file can legitimately re-group an error after a deploy.
Messages
Captured messages (strings sent through CaptureMessage, without an exception) skip stack trace normalization and group by their exact text. Keep message text stable and put variable data in attributes, otherwise every occurrence becomes its own issue:
// One issue, one alert, with the order in scope
scope.SetTag("order_id", orderID)
traceway.CaptureMessage("payment provider unreachable")
// A new issue and a new alert for every order
traceway.CaptureMessage(fmt.Sprintf("payment provider unreachable for order %d", orderID))Issue Lifecycle
- Active — When an issue first occurs
- Archived — Marked as resolved by you (hidden from the default view)
- Reopened — An archived issue that occurred again (regression detected)
Attributes on Issues
Issues carry their own attributes — the key-value metadata that was in scope when the exception occurred. If the issue is linked to a trace, it inherits the trace's attributes.
When error recording flags are enabled in middleware, additional context can be attached (configurable per client library):
- Request URL
- Query parameters
- Request body (JSON only, max 64KB)
- Request headers