Skip to content

create: report GitHub 5xx as a GitHub error; skip live-GitHub tests on it - #34419

Merged
dylan-conway merged 4 commits into
mainfrom
farm/a6cf9b9e/bun-create-github-5xx
Jul 19, 2026
Merged

dylan-conway merged 4 commits into
mainfrom
farm/a6cf9b9e/bun-create-github-5xx

Conversation

@robobun

@robobun robobun commented Jul 16, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

test/cli/install/bun-create.test.ts went red in CI on every retry on multiple lanes (builds 74144, 74149, 74151, 74152, 74153, 74154) with:

error: An internal error occurred (NPMIsDown)

The three affected tests spawn bun create https://github.com/dylan-conway/create-test, which fetches https://api.github.com/repos/dylan-conway/create-test/tarball. During the api.github.com outage on 2026-07-16 that endpoint (and /zen, /repos/..., etc.) started serving 503 Unicorn pages for GET requests, and fetch_from_github maps every 5xx from GitHub to crate::Error::NPMIsDown. That variant has been there since the original Zig implementation (it was copy/pasted from the npm-registry fetch path just below it), so a GitHub outage surfaces to users as "NPMIsDown" and to CI as a hard failure. The 429 path falls through to the same generic "internal error" message.

#29956 previously made these tests skip on GitHub 403 (rate limit), but 5xx/429 still fell through.

Fix

  • src/runtime/cli/create_command.rs: in fetch_from_github, map 5xx to GitHubIsDown (the variant bun upgrade already uses for the same case) instead of NPMIsDown. At the GithubRepository call site:
    • fold HTTPTooManyRequests into the existing 403 arm so 429 gets the same rate-limit message with the GITHUB_ACCESS_TOKEN remedy (the status code is interpolated so the message still names which one was returned);
    • add a GitHubIsDown arm that prints a server-error message naming GitHub and the template instead of falling through to the generic "An internal error occurred (...)".
      The npm-registry fetch path below still uses NPMIsDown, which is correct there.
  • test/cli/install/bun-create.test.ts: add three hermetic tests that point GITHUB_API_DOMAIN at a local TLS server returning 503/429/403 and assert the expected message for each (and that NPMIsDown/An internal error occurred is not printed). These fail on main for 503 and 429 and pass with the fix regardless of whether GitHub is up.
  • Extend the existing skip helper (now isGithubUnavailable) so the three live-GitHub tests also skip on 5xx and 429, the same way they already skip on 403.

Verification

USE_SYSTEM_BUN=1 bun test test/cli/install/bun-create.test.ts -t "should name GitHub"
# 503 and 429 fail: "An internal error occurred (NPMIsDown)" / "(HTTPTooManyRequests)"
# 403 passes (pre-existing behavior, kept verbatim)

bun bd test test/cli/install/bun-create.test.ts
# 17 pass

There is no single culprit PR for the test break itself; the live-GitHub dependency predates #29956 and the NPMIsDown label predates the Rust port (#30412). The outage is the trigger.


[review] gate passed · iteration 2 · 2 files touched

fails on main (without fix)
ASAN without fix: 2 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-create.test.ts
info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu
info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05)
info: component rust-src is up to date
info: checking for self-update (current version: 1.29.0)
bun test v1.4.0 (99aa78917)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [126.92ms]
(pass) should not crash > ["create",""] [114.76ms]
(pass) should not crash > ["create","--"] [106.43ms]
(pass) should not crash > ["create","--",""] [111.24ms]
(pass) should not crash > ["create","--help"] [106.53ms]
(pass) should create selected template with @ prefix [429.66ms]
(pass) should create selected template with @ prefix implicit `/create` [420.24ms]
(pass) should create selected template with @ prefix implicit `/create` with version [477.03ms]
Copying files... 

[17.00ms] git

[107.00ms] bun create /tmp/cr8-8przvA9/bun-create/test-template

Come hang out in bun's Discord: https://bun.com/discord

Created test-template proje
... (truncated)

release without fix: all passed
bun test v1.4.0-canary.1 (2d0d38384)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [2.23ms]
(pass) should not crash > ["create",""] [1.73ms]
(pass) should not crash > ["create","--"] [1.30ms]
(pass) should not crash > ["create","--",""] [1.56ms]
(pass) should not crash > ["create","--help"] [1.23ms]
(pass) should create selected template with @ prefix [45.09ms]
(pass) should create selected template with @ prefix implicit `/create` [47.80ms]
(pass) should create selected template with @ prefix implicit `/create` with version [43.63ms]
Copying files... 

[15.00ms] git

[15.00ms] bun create /tmp/cr8-8tLZMcv/bun-create/test-template

Come hang out in bun's Discord: https://bun.com/discord

Created test-template project successfully

# To get started, run:

  cd test-template
  bun dev

(pass) should create template from local folder [20.38ms]
(pass) should name GitHub in the error when the tarball request gets 503 [14.09ms]
(pass) should name GitHub in the error when the tarball request gets 429 [13.45ms]
(pass) should name GitHub in the error when the tarball request gets 403 [13.11ms]
(pass) should not mention cd prompt when created in cu
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-create.test.ts
info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu
info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05)
info: component rust-src is up to date
info: checking for self-update (current version: 1.29.0)
bun test v1.4.0 (99aa78917)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [120.74ms]
(pass) should not crash > ["create",""] [104.70ms]
(pass) should not crash > ["create","--"] [111.53ms]
(pass) should not crash > ["create","--",""] [106.08ms]
(pass) should not crash > ["create","--help"] [104.13ms]
(pass) should create selected template with @ prefix [513.75ms]
(pass) should create selected template with @ prefix implicit `/create` [516.78ms]
(pass) should create selected template with @ prefix implicit `/create` with version [434.24ms]
Copying files... 

[16.00ms] git

[106.00ms] bun create /tmp/cr8-8sRs1GK/bun-create/test-template

Come hang out in bun's Discord: https://bun.com/discord

Created test-template proje
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu
info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05)
info: component rust-src is up to date
info: checking for self-update (current version: 1.29.0)
[configured] bun-profile → bun (stripped) in 713ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/6] gen generated_host_exports.rs
generated_host_exports.rs: 91 exports (host=3, lazy=10, generic=78, rust=0); 243 extern-C blocks audited
[1/6] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)
info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu
info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05)
info: component rust-src is up to date
info: component rust-std is up to date

info: checking for self-update (current version: 1.29.0)
  nightly-2026-05-06-x86_64-unknown-linux-gnu unchanged - rustc 1.97.0-nightly (e95e73209 2026-05-05)

�[1m�[92m    Blocking�[0m waiting for file lock on build directory
�[1m�[92m   Compiling�[0m bun_core v0.0.0 (/workspace/bun/src/bun_core)
�[1m�[92
... (truncated)
diff hotspot
src/runtime/cli/create_command.rs   | 23 ++++++++++++--
 test/cli/install/bun-create.test.ts | 62 ++++++++++++++++++++++++++++++-------
 2 files changed, 70 insertions(+), 15 deletions(-)

gate history · 1 passed · 2 rejected · iteration 2

evidence per changed file
file                                 reads  edits  tests
src/runtime/cli/create_command.rs        2      4      0
test/cli/install/bun-create.test.ts      3      8      0

@robobun

robobun commented Jul 16, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 10:05 PM PT - Jul 18th, 2026

@autofix-ci[bot], your commit 818ceee is building: #75650

@robobun

robobun commented Jul 16, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reproduced locally during the outage: curl -s -o /dev/null -w '%{http_code}' https://api.github.com/repos/dylan-conway/create-test/tarball → 503 (also /zen → 503, /rate_limit → 200). The three new local-server tests are the hermetic gate proof and do not depend on GitHub's state.

Second commit routes 429 into the existing rate-limit arm (so it gets the GITHUB_ACCESS_TOKEN remedy) and keeps the server-error message for 5xx only; third commit splits the skip predicate from its log so the hermetic tests do not print misleading Skipping: lines.

The one-off Option::unwrap() panic from build 74166 is result.metadata.unwrap() at src/http/AsyncHTTP.rs:704 in send_sync (close-delimited body fires per-packet progress callbacks, metadata only on the first); that is fixed at the HTTP layer in #34425, which covers every send_sync caller.

Build 74206: test/cli/install/bun-create.test.ts passes on every lane except one :darwin: 14 x64 shard on agent darwin-matzo-x64-1, whose entire job timed out; on that agent the three hermetic tests plus test/bake/dev/{bundle,ecosystem,hot}.test.ts all fail with localhost ConnectionRefused/timeouts, while the other :darwin: 14 x64 agent (darwin-pita-x64-1) is green. The hermetic tests use the same GITHUB_API_DOMAIN: ${server.hostname}:${server.port} + NODE_TLS_REJECT_UNAUTHORIZED=0 pattern as bun-upgrade.test.ts. The remaining failures are timer-heap-race.test.ts (pre-existing, owned by another session) and retry-passed flakes. Ready for review.

@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 — targeted error-message fix plus a hermetic test and a skip broadening for the live-GitHub flake.

What was reviewed:

  • fetch_from_github 5xx now maps to GitHubIsDown (was NPMIsDown); the sibling npm-registry path at create_command.rs:2440 correctly stays NPMIsDown.
  • New GitHubIsDown | HTTPTooManyRequests handler mirrors the adjacent 403/404 branches; 429 previously fell through to the generic else, so this is strictly a message improvement.
  • New 503/429 tests use a local TLS server + GITHUB_API_DOMAIN override (real env var, read at create_command.rs:2260), drain both pipes concurrently, and assert exit code last.
Extended reasoning...

Overview

Two files: src/runtime/cli/create_command.rs (+13/-1) and test/cli/install/bun-create.test.ts (+42/-6). The runtime change (a) remaps 499–599 in Example::fetch_from_github from crate::Error::NPMIsDown to crate::Error::GitHubIsDown, and (b) adds a GitHubIsDown | HTTPTooManyRequests arm to the caller's error match that prints a GitHub-specific message and crashes — same shape as the existing HTTPForbidden and GitHubRepositoryNotFound arms right above and below it. The test change renames isGithubRateLimited → isGithubUnavailable, adds detection for the new message so the three live-GitHub tests skip on 5xx (as they already did on 403), and adds two hermetic tests (503, 429) that spin up a local Bun.serve with the harness tls cert and point GITHUB_API_DOMAIN at it.

Security risks

None. This is CLI error-message plumbing on a failure path; no auth, crypto, permission, or parsing changes. The test sets NODE_TLS_REJECT_UNAUTHORIZED=0 only in the spawned child's env against a localhost self-signed server — an established pattern in the suite.

Level of scrutiny

Low. The runtime change is a one-line enum swap plus a copy-pasted error-branch that follows its neighbors exactly (node.end(); progress.refresh(); pretty_error!(...); Global::crash();). The user-facing effect is only a better error message when GitHub returns 5xx/429 during bun create. I confirmed GitHubIsDown already exists in src/runtime/error.rs (used by upgrade_command.rs), that GITHUB_API_DOMAIN is actually consumed in fetch_from_github, and that the remaining NPMIsDown at create_command.rs:2440 belongs to the npm-registry example path so is correctly left alone.

Other factors

The new tests are hermetic (no live GitHub), use port: 0, using/await using for cleanup, drain stdout/stderr/exited concurrently, assert stderr contents before the exit code, and spread bunEnv. The skip-on-unavailable helper is a strict superset of the old behavior. No prior human reviews or unresolved comments on the thread. The bug hunter found nothing.

@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 — corrects a copy-paste bug where GitHub 5xx surfaced as NPMIsDown, and folds 429 into the rate-limit hint.

What was reviewed:

  • Verified GitHubIsDown exists in src/runtime/error.rs and the remaining NPMIsDown at create_command.rs:2445 is the actual npm package.json fetch path, so correctly left alone.
  • Confirmed GITHUB_API_DOMAIN is read by fetch_from_github (create_command.rs:2265), so the new hermetic test's local-server override actually routes there.
  • Checked isGithubUnavailable substrings match both new error messages (403/429 share "GitHub is rate limiting", 5xx has "GitHub returned a server error").
Extended reasoning...

Overview

Two-file change to bun create <github-url> error handling. Example::fetch_from_github was mapping 499-599 to crate::Error::NPMIsDown — a copy-paste from the adjacent npm fetch path — which surfaced to users as "An internal error occurred (NPMIsDown)" during the api.github.com outage on 2026-07-16. The PR:

  • Maps GitHub 5xx to a new GitHubIsDown arm with a dedicated user-facing message naming GitHub and the template.
  • Folds HTTPTooManyRequests (429) into the existing 403 rate-limit branch, interpolating the status code so the GITHUB_ACCESS_TOKEN remedy is shown for both.
  • Renames the test skip helper isGithubRateLimited → isGithubUnavailable and extends it to also skip live-GitHub tests on 5xx, so CI doesn't go red during GitHub outages.
  • Adds a hermetic parametrized test that points GITHUB_API_DOMAIN at a local Bun.serve returning 503/429/403 and asserts the exact per-status error text, that the skip helper recognizes each, that neither NPMIsDown nor the generic internal-error string appears, and that the exit code is 1.

Security risks

None. This is CLI error-message routing; no auth, crypto, path handling, or untrusted-input parsing changes. The test sets NODE_TLS_REJECT_UNAUTHORIZED=0 only in the spawned child's env against a localhost self-signed server, which is standard harness practice.

Level of scrutiny

Low. A wrong-enum-variant fix in a CLI error path plus an additive error branch — no control-flow changes to the success path, no new allocations or lifetimes. The status-code match arm being changed already existed; only the returned variant name changes. Verified the sibling NPMIsDown at line 2445 is genuinely the npm fetch and correctly untouched, and that upgrade_command.rs already uses GitHubIsDown for the same pattern so this brings create into line.

Other factors

  • The hermetic test follows harness conventions: using for the server, await using for the process, concurrent pipe drain via Promise.all, exit-code asserted last, port: 0.
  • The skip helper now matches on the shared substring "GitHub is rate limiting" rather than the literal "GitHub returned 403", so it correctly covers both 403 and 429 without duplication.
  • bstr::BStr::new(template) in the new pretty_error! matches how template (a &[u8]) is formatted elsewhere in the file.

@robobun
robobun force-pushed the farm/a6cf9b9e/bun-create-github-5xx branch from 242b4c4 to 2d0d383 Compare July 16, 2026 23:47
@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 56 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: 494bedcb-9dc3-4754-80a8-501876684285

📥 Commits

Reviewing files that changed from the base of the PR and between 74127d6 and 99aa789.

📒 Files selected for processing (1)
  • test/cli/install/bun-create.test.ts

Walkthrough

Changes

GitHub error handling

Layer / File(s) Summary
GitHub failure mapping
src/runtime/cli/create_command.rs
GitHub template fetches now handle both 403 and 429 responses with status-specific messages, and 499–599 responses return GitHubIsDown.
Unavailable GitHub coverage
test/cli/install/bun-create.test.ts
Tests cover 503, 429, and 403 responses, classify GitHub-unavailable failures, and update related skip conditions.

Suggested reviewers: jarred-sumner

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: GitHub 5xx handling and skipping live-GitHub tests on those failures.
Description check ✅ Passed The description covers the problem, fix, and verification, which satisfies the template's required information.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/runtime/cli/create_command.rs`:
- Line 2342: Update the status-code match range in the relevant error handling
around the GitHub response mapping to begin at 500 instead of 499, preserving
the existing upper bound of 599 and GitHubIsDown error behavior for true 5xx
responses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 187e21a1-99cb-4aef-afa4-a62b7f9fb124

📥 Commits

Reviewing files that changed from the base of the PR and between dc5748f and 2d0d383.

📒 Files selected for processing (2)
  • src/runtime/cli/create_command.rs
  • test/cli/install/bun-create.test.ts

Comment thread src/runtime/cli/create_command.rs
Comment thread test/cli/install/bun-create.test.ts

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/cli/install/bun-create.test.ts`:
- Around line 113-121: Update githubUnavailableReason to reference
GITHUB_ACCESS_TOKEN, matching the token variable required by the CLI’s
rate-limit message; leave the other unavailable-reason handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c55a82d3-1411-4dce-a6cc-c0f2682576ae

📥 Commits

Reviewing files that changed from the base of the PR and between 2d0d383 and 74127d6.

📒 Files selected for processing (1)
  • test/cli/install/bun-create.test.ts

Comment thread test/cli/install/bun-create.test.ts

@Jarred-Sumner Jarred-Sumner left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

While this fixes the specific issue, this does not answer why the test SIGABRT'd.

@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 — the earlier nit about isGithubUnavailable logging inside the hermetic assertions was addressed in 74127d6.

What was reviewed:

  • fetch_from_github status mapping: 5xx now → GitHubIsDown (matches upgrade_command.rs); the 499..=599 range is pre-existing and consistent with siblings.
  • New 429/GitHubIsDown arms at the GithubRepository call site mirror the neighboring GitHubRepositoryNotFound arm (node.end()/progress.refresh()/pretty_error!/Global::crash(), same bstr::BStr::new(template)).
  • Hermetic tests: GITHUB_API_DOMAIN is read at create_command.rs:2265 and reject_unauthorized at :2334, so the local-TLS override reaches the code under test; tls is exported from harness.
  • Skip helper split into pure githubUnavailableReason + logging isGithubUnavailable; live-GitHub tests now skip on 5xx/429 as well as 403.
Extended reasoning...

Overview

Two files. In src/runtime/cli/create_command.rs: (1) the fetch_from_github status match swaps NPMIsDown → GitHubIsDown for the pre-existing 499..=599 arm — a one-token fix for a copy-paste from the npm-registry path just below; (2) at the ExampleTag::GithubRepository call site, HTTPTooManyRequests is folded into the existing 403 rate-limit arm (status code interpolated so the message still names 403 vs 429), and a new GitHubIsDown arm prints a GitHub-specific server-error message. Both new arms copy the exact node.end() → progress.refresh() → pretty_error! → Global::crash() sequence and the bstr::BStr::new(template) formatting used by the neighboring GitHubRepositoryNotFound arm. In test/cli/install/bun-create.test.ts: three hermetic tests point GITHUB_API_DOMAIN at a local TLS Bun.serve returning 503/429/403 and assert the expected message (and absence of NPMIsDown/An internal error occurred); the pre-existing skip helper is renamed isGithubUnavailable and extended to cover 5xx/429, with the string-match logic split into a pure githubUnavailableReason predicate.

Security risks

None. This is error-message wording and CI test resilience. No new inputs are parsed, no auth/crypto/permission code touched, no memory or lifetime changes. The NODE_TLS_REJECT_UNAUTHORIZED=0 set in the test env only applies to the spawned test subprocess talking to the local self-signed test server.

Level of scrutiny

Low. The Rust change is a targeted error-variant swap plus two new error-message arms that are structurally identical to the arm directly below them; the success path is untouched. GitHubIsDown already exists in src/runtime/error.rs and is what upgrade_command.rs uses for the same status range, so this brings bun create in line with bun upgrade. The test changes follow harness conventions (port: 0, using for server/proc, {...env, ...}, concurrent pipe drain, exit-code asserted last) and are hermetic — they don't depend on GitHub's state.

Other factors

I verified the env plumbing the hermetic tests rely on: GITHUB_API_DOMAIN is read at create_command.rs:2265 and env_loader.get_tls_reject_unauthorized() at :2334, so the local-server override and self-signed-cert bypass both reach the code under test. My previous inline nit (the console.warn side effect leaking "Skipping:" lines from the hermetic assertions) was addressed in 74127d6 by splitting the predicate. Both CodeRabbit threads (the 499 lower bound and GITHUB_TOKEN naming) were answered — the range is pre-existing and shared with three sibling sites, and fetch_from_github reads GITHUB_TOKEN first (:2290-2294) — and are resolved. No outstanding reviewer comments remain.

@robobun

robobun commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

The SIGABRT is result.metadata.unwrap() at src/http/AsyncHTTP.rs:704 inside AsyncHTTP::send_sync, not in create_command.rs.

send_sync assumed the HTTP thread delivers exactly one HTTPClientResult per request, but a close-delimited body (HTTP/1.1 200 with no Content-Length and no Transfer-Encoding: chunked, body ends at FIN) fires progress_update once per packet, and to_result() only attaches the response metadata to the first of those callbacks. send_sync_callback overwrites a single slot, so depending on timing the reader either sees a truncated body or {fail: None, metadata: None, has_more: true} and unwraps None. During the outage the api.github.com → codeload redirect chain served a response in that shape.

The stack clusters match: cli::start → bun_create → CreateCommand::exec → Example::fetch_from_github → async_http.send_sync() (create_command.rs:2336) → the unwrap frame. Nothing after send_sync ran, so no pretty_error! line reached stderr and the test's expect(err).not.toContain("error:") passed before expect(out).toContain("Success!") failed.

I opened #34425 for that: it makes send_sync_callback ignore has_more callbacks (stashing the first metadata) so send_sync sees the terminal result, replaces the unwrap() with a ConnectionClosed return, and adds a hermetic test that serves a close-delimited gzip tarball via GITHUB_API_DOMAIN. send_sync has callers in bun create, bun upgrade, bun publish, bun pm view, bun audit and the standalone-binary downloader, so the fix belongs at that layer rather than here. #33501 fixed the same pattern for S3 and noted send_sync was left for a follow-up.

This PR is scoped to the 5xx/429 error-message path (the NPMIsDown case every retry hit); the unwrap is the separate once-per-run crash on the lane where one request got a close-delimited body instead of 5xx.

@dylan-conway

Copy link
Copy Markdown
Member

fix merge conflicts pls

robobun and others added 4 commits July 19, 2026 05:02
…tests on it

`bun create <github-url>` fetches https://api.github.com/repos/{owner}/{repo}/tarball.
When GitHub returns a 5xx, `fetch_from_github` mapped that to the `NPMIsDown`
error variant (a copy/paste of the npm fetch path that predates the Rust port),
which surfaces to the user as "An internal error occurred (NPMIsDown)". During
the api.github.com outage on 2026-07-16 the three GitHub-hitting tests in
bun-create.test.ts failed with that message on every retry across multiple CI
lanes (builds 74144, 74149, 74151-74154 and counting).

Fix the GitHub 5xx path to return `GitHubIsDown` (the variant `bun upgrade`
already uses for the same case) and print the same style of user-facing message
the existing 403 handler prints, naming GitHub instead of falling through to the
generic internal-error text. Cover the new message with a hermetic test that
points GITHUB_API_DOMAIN at a local TLS server returning 503/429.

On the test side, extend the existing rate-limit skip helper so the three
live-GitHub tests also skip (rather than fail) when GitHub is serving 5xx,
mirroring what #29956 already did for 403.
…x only

429 is a rate-limit response and the actionable remedy is the same
GITHUB_ACCESS_TOKEN hint already shown for 403, so fold it into that arm
(with the status code interpolated) instead of the 5xx server-error arm.
The hermetic test now asserts the per-status message and that the skip
helper recognizes all three.
@robobun
robobun force-pushed the farm/a6cf9b9e/bun-create-github-5xx branch from 99aa789 to 818ceee Compare July 19, 2026 05:05
@robobun

robobun commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main (3f65f08); #34425 already added tls to the imports, which was the only conflict. All 18 tests pass locally.

@dylan-conway
dylan-conway merged commit aa42787 into main Jul 19, 2026
6 of 39 checks passed
@dylan-conway
dylan-conway deleted the farm/a6cf9b9e/bun-create-github-5xx branch July 19, 2026 05:08

@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 — straightforward error-variant correction with hermetic test coverage; my earlier nit about the Skipping: side effect was addressed in a95dd67.

What was reviewed:

  • fetch_from_github 5xx now maps to GitHubIsDown (matching upgrade_command.rs); the 499..=599 range is pre-existing and consistent with sibling sites.
  • New 429/GitHubIsDown arms at the call site follow the exact node.end(); progress.refresh(); pretty_error!; Global::crash() pattern of the neighbouring HTTPForbidden/GitHubRepositoryNotFound arms.
  • Hermetic tests use a local TLS server via GITHUB_API_DOMAIN (same pattern as the #34425 split-body test), drain pipes concurrently, and pin the skip predicate to the Rust error text via the pure githubUnavailableReason — no more Skipping: noise.
Extended reasoning...

Overview

Two files: src/runtime/cli/create_command.rs swaps the 5xx error variant in fetch_from_github from NPMIsDown to GitHubIsDown (one token) and adds two arms at the GithubRepository call site — folding HTTPTooManyRequests into the existing 403 rate-limit message (with the status code interpolated) and a new GitHubIsDown arm with a GitHub-specific server-error message. test/cli/install/bun-create.test.ts renames the skip helper to isGithubUnavailable, splits it into a pure predicate + logging wrapper (per my earlier inline comment), extends it to cover 5xx, and adds three hermetic test.each-style tests that point GITHUB_API_DOMAIN at a local TLS server returning 503/429/403.

Security risks

None. This is CLI error-message routing and test infrastructure. No auth, crypto, permissions, or user-input parsing changes. NODE_TLS_REJECT_UNAUTHORIZED=0 is scoped to the spawned subprocess against a localhost self-signed server — the same pattern already used by bun-upgrade.test.ts and the split-body test from #34425.

Level of scrutiny

Low. The Rust change is a one-token variant swap plus two error-handling arms that copy the exact structure of the adjacent HTTPForbidden and GitHubRepositoryNotFound arms (node.end(); progress.refresh(); pretty_error!(...); Global::crash();). GitHubIsDown is the variant upgrade_command.rs:313/:719 already use for the identical case, so this brings bun create in line with bun upgrade. The npm fetch path below still uses NPMIsDown, which is correct there. The 499..=599 range is pre-existing and shared across three other sites — coderabbit raised then withdrew that.

Other factors

  • All three prior inline threads are resolved: my console.warn side-effect nit (fixed by splitting out githubUnavailableReason), coderabbit's 499..=599 (pre-existing, out of scope), and coderabbit's GITHUB_TOKEN wording (fetch_from_github reads it first).
  • The hermetic tests are well-formed: using/await using for cleanup, port: 0, concurrent Promise.all on stdout/stderr/exited, exit-code assertion last, and they assert both the positive (toContain(expected)) and negative (not.toContain("NPMIsDown"), not.toContain("An internal error occurred")) contracts. The githubUnavailableReason(err) assertion pins the skip predicate to the actual Rust output so a future wording change can't silently stop the live tests from skipping.
  • dylan-conway's only request was to rebase for a merge conflict, which was done (the tls import from #34425 was the only overlap). Gate evidence in the PR body shows the 503/429 tests fail on main and pass with the fix; 18 tests pass post-rebase.

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.

3 participants