Skip to content

feat(wasm-debug-files): Add prepare command for WASM debug setup - #1572

Open
d2anamaria wants to merge 15 commits into
mainfrom
ana/feat/wasm/debug-file-pipeline
Open

d2anamaria wants to merge 15 commits into
mainfrom
ana/feat/wasm/debug-file-pipeline

Conversation

@d2anamaria

@d2anamaria d2anamaria commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Preparing WebAssembly for Sentry takes two tools today. You run wasm-split to inject a build_id and pull DWARF out into a companion file, then run sentry debug-files upload --type wasm on that companion. Nothing tells you when a module was built without usable debug info, so the mistake surfaces later as an unsymbolicated stack trace.

Solution

sentry debug-files prepare <path>... does both steps in one command.

sentry debug-files prepare ./dist

It scans the given files and directories for .wasm modules, splits the ones carrying inline DWARF, and uploads the companions. Org and project are auto-detected from DSN, env vars, or config defaults. --dry-run and --no-upload need no credentials.

What it does per module

For a module with inline DWARF:

  1. Inject a build_id if it has none.
  2. Write a *.debug.wasm companion keeping every section, including Code and DWARF.
  3. Strip the .debug_* sections from the deployable module, in place.
  4. Point the deployable at the companion via external_debug_info.
  5. Upload the companion.

The deployable keeps its original path, so your build artifact does not move. Both files carry the same build_id, which is how Sentry matches a stack frame to its debug file. The companion keeps the Code section because DWARF addresses are relative to it.

A module that cannot be split is still stamped with a build_id, then reported with a warning. Stamping matters: without a build_id a module can never be symbolicated, not even from a debug file uploaded later. Nothing is uploaded for it.

Outcome Meaning Uploaded
Split Had DWARF; companion written Yes
Already prepared Companion with matching build_id already exists Yes
Would split --dry-run preview No
Skipped Not splittable; stamped, warning printed No

Warnings

A module without usable debug info does not fail the run unless --require-dwarf is set. The warning says why it was skipped:

  • no line-level symbolication (name/symtab only)
  • no debug information; rebuild with DWARF (Emscripten -g, wasm-pack dwarf-debug-info)
  • already stripped (build_id present, no debug sections); splitting would produce a useless companion
  • has external_debug_info but no local companion with matching build_id

Re-running is safe. An already-prepared pair is detected and left alone rather than overwritten with an empty companion, and a module keeps the build_id it was stamped with on the first run.

Options

Flag Effect
--dry-run Classify only; write nothing, upload nothing
--no-upload Split, but skip the upload
--require-dwarf Fail if any scanned module lacks DWARF
--out-dir <DIR> Put companions here; deployables are always stripped in place
--strip-names Also drop the name section from split deployables; the companion keeps it
--build-id <UUID> Use a fixed build id instead of a random one, for exactly one module that has none
--include-sources Also upload a source bundle per companion
--wait / --wait-for <SECS> Wait for server-side processing
--ignore <GLOB> / --ignore-file <FILE> Skip paths while scanning

--require-dwarf is the CI guard, and it runs before anything is uploaded, so a build missing debug info fails without pushing files first. A module pointing at an external companion counts as having DWARF, so a dangling pointer does not fail the build.

--ignore globs are relative to the tree you point at: --ignore 'vendor/**' with prepare ./dist means ./dist/vendor.

Scanning rules

Directories are walked recursively. *.debug.wasm files are skipped, since they are outputs of an earlier run. Naming a non-.wasm file directly is an error; a directory with no modules is just an empty scan.

Automation

--json reports the outcome per module, so a build script can act on the classification instead of grepping logs:

{
  "org": "my-org",
  "project": "my-project",
  "uploaded": true,
  "filesUploaded": 1,
  "modules": [
    {
      "path": "dist/app.wasm",
      "action": "split",
      "quality": "dwarf",
      "buildId": "…",
      "companion": "dist/app.debug.wasm"
    }
  ]
}

The command exits non-zero when --require-dwarf fails, and when a companion fails server-side processing under --wait.

Relationship to wasm-split

sentry wasm-split splits one module and stops there. This command is the pipeline around it: it
scans directories, classifies each module's debug quality, skips what it should not touch, and
uploads the companions. The split itself is the same splitWasm call.

Elsewhere the CLI reads debug files through @sentry/symbolic that wrapper (only reads).
This command rewrites modules: it injects build_id, strips .debug_*, and adds
external_debug_info. So it parses sections directly.

That is also why the two disagree on build_id. This command follows the tool convention;
symbolic reads it one byte shifted. The id sent here is advisory — the server re-parses the module
and stores its own key — so nothing breaks today. See
getsentry/symbolic#1069.

Limitations

  • A module without DWARF gets a build_id but no debug file. Rebuild with DWARF and re-run to get line-level frames; the build_id is preserved.
  • external_debug_info records the companion filename only. prepare does not expose wasm-split's --external-dwarf-url; reach for sentry wasm-split if you need a custom URL. Sentry resolves by build_id, so this does not affect symbolication.
  • Splitting always strips. There is no mode that writes a companion and leaves the deployable intact.
  • With --out-dir, re-running without the same --out-dir will not find the companion and reports a dangling reference.

@vercel

vercel Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
cli Ready Ready Preview Sep 28, 2026 1:09pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
sentry-local Skipped Skipped Sep 28, 2026 1:09pm UTC

Request Review

@d2anamaria
d2anamaria marked this pull request as draft September 10, 2026 10:14
Comment thread packages/cli/src/lib/wasm/prepare.ts Outdated

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/cli/src/lib/wasm/prepare.ts
Comment thread packages/cli/src/lib/wasm/prepare.ts Outdated
Comment thread packages/cli/src/commands/debug-files/prepare.ts Outdated
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 10, 2026 14:00 Inactive
@d2anamaria

Copy link
Copy Markdown
Contributor Author

A deploy .wasm can end up with external_debug_info (pointer to companion) but no build_id when the module was split outside wasm-split (custom script/tool) and the build never stamped ids (no --build-id / equivalent at compile). The companion may still be on disk with its own id. Today prepare skips with a warning and stamps a new random id on the deploy module only, which breaks the pair permanently. Would it be safe to treat this as repairable — read the companion's id (or generate one and write it to both), instead of skipping upload?

@BYK

BYK commented Sep 10, 2026

Copy link
Copy Markdown
Member

Would it be safe to treat this as repairable — read the companion's id (or generate one and write it to both), instead of skipping upload?

Sounds like we should, yes. Also a simple warning in this case sounds like the wrong action as we are essentially uploading broken stuff?

Comment thread packages/cli/src/lib/wasm/prepare.ts
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 15, 2026 12:43 Inactive
@d2anamaria
d2anamaria force-pushed the ana/feat/wasm/debug-file-pipeline branch from 344b5b7 to cf5ae11 Compare September 16, 2026 12:07
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 16, 2026 12:07 Inactive
@d2anamaria
d2anamaria changed the base branch from main to ana/feat/wasm/port-wasm-split September 16, 2026 12:10
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 16, 2026 12:28 Inactive
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 16, 2026 13:12 Inactive
@d2anamaria
d2anamaria force-pushed the ana/feat/wasm/port-wasm-split branch 4 times, most recently from 0fc4d8f to a408240 Compare September 16, 2026 13:47
@vercel
vercel Bot temporarily deployed to Preview – sentry-local September 16, 2026 14:44 Inactive
- reuse shared readSourceFile in bundle-sources instead of an inline
  readFileSync try/catch
- build the prepare report by pushing module sections into the summary
  array instead of spread/flatMap intermediates
- name all thirteen non-custom wasm section ids as constants in
  SECTION_ORDER
- trim the prepare docs fragment: drop the wasm-split parity note and
  shorten the idempotency line
- Move buildIgnoreMatcher into lib/scan/ignore.ts
- Reuse it in debug-files prepare and sourcemap commands

@loewenheim loewenheim left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a high level I think this command is misnamed, on two counts:

  1. It doesn't apply to debug files in general, only wasm.
  2. "Prepare" doesn't sound like it uploads files, it sounds like something you call before you upload them.

I'm just spitballing, but I could see this as a --split-wasm flag on debug-files upload that splits wasm files with default options (and you can either add options to customize the wasm-split behavior or tell users to run wasm-split manually if they need to customize it).

@d2anamaria

Copy link
Copy Markdown
Contributor Author

I'm just spitballing, but I could see this as a --split-wasm flag on debug-files upload that splits wasm files with default options (and you can either add options to customize the wasm-split behavior or tell users to run wasm-split manually if they need to customize it).

I agree the name is a bit misleading, but I'd fix the name rather than folding it into upload. This command rewrites your build artifacts, while upload is read-only. Carrying the wasm-split flags over would bloat upload with options that do nothing unless you're uploading wasm.

@loewenheim

Copy link
Copy Markdown

Yeah, that's fair both on the read-only point and the options point. Again, just a thought: maybe the new command could be folded into wasm-split.

- name companions <stem>.<build_id>.debug.wasm instead of <stem>.debug.wasm
- resolve build id before naming so unstamped modules get unique filenames
- write external_debug_info as a path relative to the module, not basename only
- dry-run reports exact path when id is known, <build-id> placeholder otherwise
- update prepare help text and docs to match the new companion naming
Comment thread packages/cli/src/lib/wasm/prepare.ts
@d2anamaria

Copy link
Copy Markdown
Contributor Author

Yeah, that's fair both on the read-only point and the options point. Again, just a thought: maybe the new command could be folded into wasm-split.

wasm-split handles one specific file at a time. This command scans for multiple wasm files in a directory. Maybe rename it to wasm-upload

…dule

- Split the run in two phases: collect companion pointers, then prepare
- Step 1 reads only the short header of each section
- Step 1 jumps over section contents, so big DWARF files stay fast
- Step 1 keeps only a list of companion paths, not file contents
- Step 2 reads and splits each module as before
- Leave referenced companions untouched, so their DWARF is kept

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ac78128. Configure here.

Comment thread packages/cli/src/commands/debug-files/wasm-upload.ts

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – cli — b1119f51 Deployed Sep 28, 2026 by vercel[bot]
Preview – sentry-local — b1119f51 Deployed Sep 28, 2026 by vercel[bot]
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.

3 participants