Skip to content

fix(build): disable identifier minification to fix marked crash - #617

Merged
betegon merged 1 commit into
mainfrom
fix/bun-minifier-crash
Mar 31, 2026
Merged

fix(build): disable identifier minification to fix marked crash#617
betegon merged 1 commit into
mainfrom
fix/bun-minifier-crash

Conversation

@betegon

@betegon betegon commented Mar 31, 2026

Copy link
Copy Markdown
Member

Summary

Fixes the compiled binary crash that affected all commands rendering markdown output (auth status, issue explain, etc.):

TypeError: _4 is not a function. (In '_4(_4.tokens)', '_4' is an instance of Object)

Root Cause

Bun's identifier minification assigns short names (_4, _5, etc.) to all functions/variables. A name collision caused renderInline (a function in markdown.ts) to get the same minified name as an unrelated object. When renderOneInline calls renderInline(token.tokens), the minified code calls _4(_4.tokens) — but _4 is the object, not the function.

Triggered by PR #602 (716e2ba) which removed ~380 lines of code, shifting the minifier's naming sequence. The bug is in Bun's bundler, not our source code — any future code change could re-trigger it.

Fix

Change minify: true to minify: { whitespace: true, syntax: true, identifiers: false } in script/build.ts. This keeps whitespace removal and syntax transforms while avoiding identifier renaming.

Size impact: Bundle grows from 2.87 MB to 3.64 MB raw (~27%). Gzip compression absorbs most of the difference since original identifier names compress well.

Bisect

Test plan

  • SENTRY_CLI_BINARY=./dist-bin/sentry-darwin-arm64 bun test --timeout 15000 test/e2e — 122 pass, 0 fail
  • SENTRY_AUTH_TOKEN=test ./dist-bin/sentry-darwin-arm64 auth status — renders markdown without crash

Made with Cursor

Bun's identifier minification creates name collisions in the `marked`
library's token walker — `renderInline` (a function) gets the same
minified name as an unrelated object, causing `auth status` and other
markdown-rendering paths to crash with:

  TypeError: _4 is not a function. (In '_4(_4.tokens)', '_4' is an instance of Object)

The collision was triggered by PR #602 removing ~380 lines of code,
which shifted the minifier's naming sequence. Any future code change
could re-trigger it since it depends on exact identifier ordering.

Fix: use `minify: { whitespace: true, syntax: true, identifiers: false }`
instead of `minify: true`. This keeps whitespace removal and syntax
transforms (most of the size savings) while avoiding the fragile
identifier renaming. Bundle grows from 2.87 MB to 3.64 MB raw, but
gzip compression absorbs most of the difference.

Made-with: Cursor
@github-actions

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (auth) Enforce auth by default in buildCommand by betegon in #611
  • (skill) Add eval framework to measure SKILL.md effectiveness by BYK in #602
  • (telemetry) Add seer.outcome span tag for Seer command metrics by BYK in #609
  • (upgrade) Show changelog summary during CLI upgrade by BYK in #594

Bug Fixes 🐛

Upgrade

  • Prevent spinner freeze during delta patch application by BYK in #608
  • Indent changelog, add emoji to heading, hide empty sections by BYK in #604

Other

  • (build) Disable identifier minification to fix marked crash by betegon in #617
  • (dashboard) Reject MRI queries with actionable tracemetrics guidance by BYK in #601
  • (init) Prompt/spinner ordering by betegon in #610
  • (skill) Avoid unnecessary auth, reinforce auto-detection, fix field examples by BYK in #599
  • (test) Fix CI hang, auth guard tests, and PR fix(init): prompt/spinner ordering #610 test rewrite by betegon in #616
  • 2 bug fixes — subcommand crash, negative span depth, pagination JSON parse by cursor in #607

Documentation 📚

  • (skill) Document dashboard widget constraints and deprecated datasets by BYK in #605
  • Fix documentation gaps and embed skill files at build time by cursor in #606

Internal Changes 🔧

  • Regenerate skill files and command docs by github-actions[bot] in 664362ca

🤖 This preview updates automatically when you update the PR.

@github-actions

Copy link
Copy Markdown
Contributor

Codecov Results 📊

129 passed | Total: 129 | Pass Rate: 100% | Execution Time: 0ms

📊 Comparison with Base Branch

Metric Change
Total Tests
Passed Tests
Failed Tests
Skipped Tests

✨ No test changes detected

All tests are passing successfully.

✅ Patch coverage is 100.00%. Project has 1359 uncovered lines.
❌ Project coverage is 95.43%. Comparing base (base) to head (head).

Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
- Coverage    95.45%    95.43%    -0.02%
==========================================
  Files          204       204         —
  Lines        29739     29739         —
  Branches         0         0         —
==========================================
+ Hits         28387     28380        -7
- Misses        1352      1359        +7
- Partials         0         0         —

Generated by Codecov Action

@betegon
betegon merged commit 4146d99 into main Mar 31, 2026
23 checks passed
@betegon
betegon deleted the fix/bun-minifier-crash branch March 31, 2026 21:20
BYK added a commit that referenced this pull request Apr 1, 2026
… bug

Replace Bun.build() with esbuild in the binary build's bundling step
(Step 1). Bun's identifier minification has an unfixed collision bug
(oven-sh/bun#14585) where minified output produces name collisions
across module scopes, causing runtime 'X is not a function' errors.
The previous workaround (PR #617) disabled identifier minification
entirely, losing ~27% bundle size reduction.

esbuild's minifier is more mature and handles identifier mangling
correctly. This restores full minification (whitespace + syntax +
identifiers) while also fixing a long-standing sourcemap quality
issue: Bun's sourcemaps had an empty names array (0 entries), while
esbuild produces 27,860 names across 1,006 source files — giving
Sentry much better stack trace resolution.

Size comparison (esbuild vs Bun.build with identifiers:false):
- JS bundle: 2.82 MB vs 3.64 MB (-22%)
- Binary gzip: 28.39 MB vs 28.40 MB (negligible)
- Sourcemap names: 27,860 vs 0 (massive improvement)

Verified: 122 E2E tests pass, auth status renders correctly,
debug ID injection works, Bun.build({compile}) accepts esbuild output.
BYK added a commit that referenced this pull request Apr 1, 2026
… bug (#619)

## Summary

- Replace `Bun.build()` with esbuild in the binary build's Step 1 (TS →
JS bundling)
- Restores full identifier minification that was disabled in #617
- Fixes sourcemap quality: esbuild produces 27,860 names vs Bun's empty
array

## Problem

Bun's identifier minification has an unfixed collision bug
([oven-sh/bun#14585](oven-sh/bun#14585)) where
minified output produces name collisions across module scopes, causing
runtime `X is not a function` errors. PR #617 worked around this by
disabling identifier minification (`identifiers: false`), but that loses
~22% bundle size reduction and still uses Bun's sourcemaps which have an
empty `names` array.

The upstream fix
([oven-sh/bun#17930](oven-sh/bun#17930)) was
acknowledged as a workaround — the real bug in Bun's renamer/hoisting
code was never properly fixed. We still hit collisions on Bun 1.3.11.

## Solution

Use esbuild (already a devDependency for the npm bundle) for the binary
build's bundling step. The compile step still uses `Bun.build({ compile:
true })` since that's the only way to produce native Bun binaries.
esbuild's output is standard ESM that `Bun.build({ compile })` accepts
without issues.

Config: `platform: "node"`, `target: "esnext"`, `format: "esm"`,
`external: ["bun:*"]`, `sourcemap: "external"`, `minify: true`

## Size comparison

| Metric | PR #617 (identifiers:false) | This PR (esbuild full minify) |
|--------|---------------------------|-------------------------------|
| JS bundle | 3.64 MB | 2.82 MB (**-22%**) |
| Binary (gzip) | ~28.4 MB | ~28.4 MB |
| Sourcemap names | 0 (empty!) | 27,860 |
| Sourcemap sources | N/A | 1,006 |

## Verification

- `auth status` (PR #617 crash scenario): renders markdown correctly
- E2E tests: 122 pass, 0 fail, 3 skip
- Debug ID injection: works (UUID generated)
- `Bun.build({ compile })` accepts esbuild ESM output
- Lint: clean

## Changes

Single file: `script/build.ts`
- Added esbuild import, replaced `Bun.build()` in `bundleJs()` with
`esbuild()`
- Added `mkdirSync("dist-bin")` since esbuild doesn't auto-create output
dirs
- Updated JSDoc

Made with [OpenCode](https://opencode.ai)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant