Stable Sentry error grouping across deploys - #1781
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | ccc859f | Aug 28 2026, 12:04 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | ccc859f | Commit Preview URL Branch Preview URL |
Aug 28 2026, 12:03 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
RhysSullivan
force-pushed
the
fix/stable-sentry-fingerprints
branch
from
August 27, 2026 20:25
545ee73 to
7b82895
Compare
Normalize build content hashes out of the grouping key in the cloud, desktop main and desktop renderer Sentry inits, and merge address-keyed Chromium soft-assert minidumps into one fingerprint.
RhysSullivan
force-pushed
the
fix/stable-sentry-fingerprints
branch
from
August 28, 2026 00:00
5038374 to
ccc859f
Compare
RhysSullivan
marked this pull request as ready for review
August 28, 2026 01:28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The same crash kept opening a brand-new issue after every deploy, so a single bug had no count, no history and no regression signal — one problem spread across many issues. Our bundles ship content-hashed chunks and those frames are not resolved back to source, so error grouping falls back to minified chunk names like
execution-rate-limit-<hash>, and the hash rotates on every build. On desktop the same effect splits one renderer bug across several issues, and Chromium soft-assert minidumps split by load address.Fix
A shared
@executor-js/sdk/sentry-groupinghelper computes an explicit Sentryfingerprintwith the volatile hash segment removed, wired into the cloud worker/DObeforeSend, the desktop main init and the desktop renderer init. Each process installs the samewithStableGroupingFingerprinthelper rather than its own copy, and the options objects handed toSentry.init/withSentryare assembled in the modules their tests can reach.The event itself is sent untouched — filenames keep their hashes, so server-side sourcemap resolution is unaffected. Only the grouping key is normalized, and only for events that actually carry a hash; everything else keeps the default grouping algorithm. Desktop additionally collapses
DumpWithoutCrashingminidumps onto one fingerprint. Nothing is dropped, downgraded or filtered.Mechanism choice: the SDKs offer no sourcemap-based grouping switch. The alternative is uploading sourcemaps per release so grouping happens on original frames — worth doing separately, since it also fixes the frames engineers read — but it is a release-pipeline change and does nothing for native minidumps, so
beforeSendfingerprints are the minimal reliable mechanism.Testing
e2e:
vitest run --project cloud cloud/sentry-otel-correlation.test.ts— black-box against the running worker. Its correlation payload exists only if the worker actually ran thebeforeSendfromcloudSentryOptions, so this is the proof that the hook is installed and still captures. Three consecutive green runs, ~20s each.Grouping keys are decided inside the Sentry SDK and never reach a product surface, and a locally served worker/renderer is not content-hashed, so the e2e harness has nothing to observe. Coverage is unit-level by exception, split so both halves are checked:
packages/core/sdk): the same frame across two chunk hashes fingerprints identically; different modules and different callers stay distinct; hash-free events pass through untouched. The "is this a hash?" threshold is pinned from both sides, so relaxing it — the tempting fix for the word-shaped hashes it deliberately misses — fails instead of silently merging real chunk names likeconnections-Settings. Two chunks sharing a name are separated by their caller chain, and shrinking that chain to the crashing frame fails.apps/cloud/src/observability,apps/desktop/src/main): the exact options object handed towithSentry,instrumentDurableObjectWithSentryand the main-processSentry.initis asserted to carry the fingerprinting hook, so unhooking the normalizer fails a test rather than passing quietly.Sentry.initlives inpackages/app, which has no test runner. ItsbeforeSendis a one-symbol reference to the covered helper, but deleting that line would not fail a test.Checked against a real desktop build: 146 of 147 chunk names normalize; the one holdout is a word-shaped hash left alone on purpose.
beforeSendnow runs two independent stages. The capture-owner pass decides whether an event is reported at all — a cause the session Durable Object already claimed is dropped — and the grouping pass then decides how whatever survives is grouped. A dropped event is never fingerprinted, and a report the DO owns still gets a stable fingerprint across chunk hashes. Both directions are asserted.