Skip to content

cli: exit 1 when bun build --app is given a --target other than bun - #38581

Open
robobun wants to merge 1 commit into
mainfrom
farm/83b63dba/build-app-target-exit
Open

robobun wants to merge 1 commit into
mainfrom
farm/83b63dba/build-app-target-exit

Conversation

@robobun

@robobun robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • bun build --app --target=node ./bun.app.ts prints error: target must be 'bun' when using --app. Received: Node and then carries on: the config file is evaluated, the build runs, and the process exits 0 when the build succeeds.
  • The --app arm of the --target check in src/runtime/cli/Arguments.rs (parse_build_command_options) prints the message but never exits. The --bytecode arm directly above it prints the same kind of message and calls Global::exit(1).
  • The missing exit dates back to the commit that added the arm (e93c5ad, in the Zig Arguments.zig): it was written as a copy of the --bytecode arm without its Global.exit(1). The Rust port reproduced it as-is.

Fix

  • Add Global::exit(1) after the error message, so --app with a non-bun target behaves like --bytecode with a non-bun target: one error line, exit 1, nothing built.
  • Exiting (rather than dropping the check or downgrading it to a warning) is the right outcome: an --app build always produces a Bun server plus browser client bundles and never reads --target (src/runtime/bake/production.rs builds its own transpilers), so a different --target is a request the build cannot honor. Printing error: and then exiting 0 hides exactly that from scripts and CI.
  • Test: test/bundler/cli.test.ts ("CLI argument error messages > --app --target"). --target=node and --target=browser must produce exactly the error line on stderr, nothing on stdout (the config file logs a marker when it is evaluated), and exit 1; --target=bun must still start the build. The two rejected cases fail on the current release (stderr continues with the bake banner, Loading configuration and the config error, and the marker shows up on stdout) and pass with this change.
  • Also verified the new tests under the debug ASAN build with detect_leaks=1, since the fix adds a new process-exit path during argument parsing.

Background

  • bun build --app is the production build for Bun's experimental full-stack framework support (Bake). It is gated behind a feature flag that is on in canary and debug builds and can be enabled with BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE=1; the test harness's bunEnv sets that variable, which is how the test runs on release builds as well.
  • Global::exit(1) flushes stdout/stderr and exits the process; it is the idiom used by the other fatal argument errors in this function (Global::crash() is the same thing with the exit code fixed at 1).

The --app arm of the --target check printed the error and then let the
build continue, so the config was still evaluated and the build exited 0.
Exit after printing, the same way the --bytecode arm next to it does.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c7153a93-b4ef-4319-be2e-7300602f59a1

📥 Commits

Reviewing files that changed from the base of the PR and between eabb96d and 72eaa41.

📒 Files selected for processing (2)
  • src/runtime/cli/Arguments.rs
  • test/bundler/cli.test.ts

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Status: fix pushed, waiting on CI.

Reproduced on bun 1.4.0 with BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE=1 bun build --app --target=node ./bun.app.ts: the target must be 'bun' when using --app error is printed, then Loading configuration follows and the build runs anyway. With this change the same command prints only the error and exits 1, matching --bytecode --target=node.

The new cases in test/bundler/cli.test.ts fail on 1.4.0 and pass with this branch (also under the debug ASAN build with leak detection on).

@claude claude 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.

LGTM — one-line fix that adds the missing Global::exit(1) to the --app target check, mirroring the --bytecode arm directly above it.

What was reviewed:

  • Confirmed the --bytecode arm at Arguments.rs:2188-2199 uses the identical print-then-Global::exit(1) pattern; the new line matches it exactly.
  • Tests follow harness conventions (tempDir, bunEnv, concurrent pipe drain, exit code asserted last) and cover both rejected targets plus the --target=bun pass-through.
  • Verified bunEnv sets BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE so the test runs on release builds; the stdout marker in bun.app.ts proves the build did not start.
Extended reasoning...

Overview

Single-line change in src/runtime/cli/Arguments.rs (parse_build_command_options): adds Global::exit(1) after the existing error print for bun build --app --target=<not-bun>. The --bytecode arm three lines above already does exactly this; the --app arm was written without the exit call. Accompanied by three new test cases in test/bundler/cli.test.ts.

Security risks

None. This is CLI argument validation for an experimental build mode; the change makes an already-printed error: line actually terminate the process instead of continuing to build.

Level of scrutiny

Low. The fix is mechanical — it copies the exit call from the sibling arm immediately above. Global::exit(1) is the established idiom for fatal argument errors throughout this function (per the PR description and confirmed by reading the surrounding code). The affected feature (--app / Bake) is experimental and behind a feature flag.

Other factors

  • Tests are well-constructed: test.each over node/browser, exact stderr assertion via normalizeBunSnapshot, empty-stdout assertion using a config-file marker to prove the build never started, and a positive case for --target=bun. Pipes are drained concurrently, resources use using/await using, and the tests are placed alongside the existing "CLI argument error messages" describe block.
  • Confirmed bunEnv in test/harness.ts:86 sets BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE, so the test's comment about release-build coverage is accurate.
  • No prior reviewer comments to address; no outstanding concerns from the timeline.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant