Skip to content

fix(sourcemap): adopt a debug ID already present on the sourcemap - #1496

Merged
BYK merged 3 commits into
mainfrom
fix/sourcemap-adopt-existing-map-debug-id
Aug 28, 2026
Merged

fix(sourcemap): adopt a debug ID already present on the sourcemap#1496
BYK merged 3 commits into
mainfrom
fix/sourcemap-adopt-existing-map-debug-id

Conversation

@msonnb

@msonnb msonnb commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

sentry sourcemap inject and sentry sourcemap upload only looked for an existing debug ID in the JS file (//# debugId=). If the JS had no such comment but the sourcemap already carried debug_id/debugId, the CLI minted a brand-new content-derived ID, rewrote the JS, and overwrote the map's field.

Why it matters

Sentry's JavaScript bundler plugins support sourcemaps.disable: 'disable-upload': the plugin injects a runtime _sentryDebugIds snippet into the bundle during the build and stamps that same ID into the emitted .js.map (getsentry/sentry-javascript#23619). It deliberately does not append //# debugId= to the bundle, because rewriting the bundle after emit invalidates subresource-integrity hashes computed during the build (getsentry/sentry-javascript-bundler-plugins#949 — the reporter serves <script integrity="…"> from webpack-assets-manifest).

Those users then run sentry sourcemap upload ./dist. Before this change the CLI minted a different ID, so the ID the SDK reported at runtime never matched what Sentry indexed and nothing symbolicated — plus the rewrite broke the SRI hashes they were protecting.

What changed

Debug ID precedence when resolving a file pair:

  1. //# debugId= in the JS → use it (unchanged; it's the on-disk spec marker)
  2. New: otherwise, a valid debug_id/debugId on the sourcemap → adopt it, wasInjected: false, neither file is written
  3. Otherwise, mint from content (unchanged)

debug_id wins over debugId. A value that isn't a well-formed UUID is treated as absent and falls through to minting.

Case 2 deliberately does not prepend the IIFE snippet and does not offset mappings: the bundle already has the plugin's own _sentryDebugIds writer (a second one under a different stack key makes the runtime mapping ambiguous), and the plugin's map already lines up with the un-offset bundle.

Covers external maps, inline (base64 data:) maps, --dry-run, and the discovery read behind sourcemap resolve. This is default behavior — not gated behind a new flag, and --no-rewrite is unchanged.

  • src/lib/sourcemap/debug-id.ts — new readSourcemapDebugId(); early return in injectDebugId() and injectInlineDebugId()
  • src/lib/sourcemap/inject.ts — new readMapDebugId() helper wired into the --dry-run branch and resolveDirectorySourcemaps()

The upload path needed no change — buildArtifactPair() already puts the resolved debugId on both entries — but it's covered end to end by new tests rather than assumed.

On v3 parity

Worth recording, since the flag list in the migration guide reads as a capability loss:

  • --debug-id-reference was an upload flag, and narrower than it sounds. Its help text: "By default Debug ID reference has to be present both in the source and the related sourcemap. But in cases of binary bundles, the tool can't verify presence of the Debug ID. This flag allows use of Debug ID from the linked sourcemap." It's a verification relaxation for binary bundles (Hermes bytecode, where a //# debugId= comment is impossible) — it injects nothing. This is why it shows up in the React Native docs right after copy-debugid.js.
  • v3's sourcemaps inject already adopted the map's ID by default, no flag — but it still rewrote both files. The debug_id_fresh boolean in sourcemaps.rs only selects a report bucket; fixup_js_file() still injects the snippet and shifts the mappings either way. So Ignored: The following sourcemap files already have debug ids meant "no new ID minted", not "file untouched".

So this PR matches v3 on which ID wins and is intentionally stricter on what gets written — leaving both files byte-identical is precisely what makes the integrity-hash workflow work.

Known gap, flagged for review: a map carrying a debug_id whose bundle has neither a comment nor a plugin snippet now gets no runtime registration at all (v3 would have injected one). It doesn't affect the two motivating workflows — Hermes can't be injected anyway, and disable-upload already has the snippet — but if we want v3 parity there, the fix would be to detect _sentryDebugIdIdentifier in the bundle and fall back to injecting when absent. Left out because sniffing "does this bundle self-register?" from a substring is fragile.

Tests

test/lib/sourcemap/inject.test.ts — 8 new cases: external debug_id; the debugId spelling; precedence between the two; inline map; JS comment wins over a conflicting map field; malformed value falls through to minting; --dry-run reports the adopted ID; repeat runs stay a no-op. Each asserts the JS and map are byte-identical.

test/commands/sourcemap/upload.test.ts — 2 new cases asserting uploaded artifacts carry the adopted ID on both the minified_source and source_map entries, for external and inline maps.

Docs

Added a bullet to migrating-from-v3.md noting the capability is back as automatic default behavior, with the accurate v3 semantics.

Verification

  • pnpm lint — clean
  • pnpm typecheck — clean
  • pnpm test:unit — 9334 passed. The 6 failures in test/lib/time-range.test.ts are pre-existing and unrelated (timezone-dependent assertions); confirmed identical on a clean tree via git stash.

🤖 Generated with Claude Code

`inject` and `upload` only looked for an existing debug ID in the JS file
(`//# debugId=`). When the JS had no such comment but the sourcemap already
carried `debug_id`/`debugId`, the CLI minted a new content-derived ID,
rewrote the JS, and overwrote the map's field.

That breaks Sentry's bundler plugins running with
`sourcemaps.disable: 'disable-upload'`. Those builds inject a runtime
`_sentryDebugIds` snippet and stamp the same ID onto the emitted `.js.map`,
but deliberately leave the bundle without a `//# debugId=` comment —
rewriting it after emit invalidates subresource-integrity hashes computed
during the build (getsentry/sentry-javascript-bundler-plugins#949). A later
`sentry sourcemap upload ./dist` minted a different ID, so what the SDK
reported at runtime never matched what Sentry indexed.

Debug ID precedence is now:

1. `//# debugId=` in the JS (unchanged; the on-disk spec marker)
2. a valid `debug_id`/`debugId` on the sourcemap — adopted as-is
3. otherwise, mint from content (unchanged)

In case 2 neither file is written: no IIFE snippet (the bundle already has
the plugin's own `_sentryDebugIds` writer, and a second one under a
different stack key makes the runtime mapping ambiguous) and no `mappings`
offset (the plugin's map already lines up with the un-offset bundle).
`debug_id` wins over `debugId`; a value that isn't a well-formed UUID is
treated as absent and falls through to minting.

Applies to external and inline maps, to `--dry-run`, and to the discovery
read behind `sourcemap resolve`. Default behavior, matching v3 — not gated
behind a flag, and `--no-rewrite` is unchanged.

Note this is slightly stricter than v3's `sourcemaps inject`, which adopted
the map's ID but still added its snippet to the bundle and re-serialized the
map (its "Ignored: … already have debug ids" report meant "no new ID minted",
not "file untouched"). Leaving both files byte-identical is what makes the
integrity-hash workflow above work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cli Ready Ready Preview Aug 28, 2026 8:01am

Request Review

@BYK
BYK marked this pull request as ready for review August 27, 2026 13:10
@github-actions github-actions Bot added the risk: medium PR risk score: medium label Aug 27, 2026
Comment thread packages/cli/src/lib/sourcemap/debug-id.ts Outdated
Comment thread packages/cli/src/lib/sourcemap/inject.ts Outdated
Comment thread packages/cli/test/commands/sourcemap/upload.test.ts Outdated
@BYK
BYK merged commit 23ece5c into main Aug 28, 2026
34 checks passed
@BYK
BYK deleted the fix/sourcemap-adopt-existing-map-debug-id branch August 28, 2026 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants