[miniflare] Improve error diagnostics in the Browser Run binding worker#13971
Conversation
🦋 Changeset detectedLatest commit: bb6eb87 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Codeowners approval required for this PR:
Show detailed file reviewers |
There was a problem hiding this comment.
Small nit — text.length is the character count, not the byte count. The suffix says "bytes total" which is misleading for multi-byte content. Not a blocker since the diagnostic is for developer consumption only, but worth fixing while you're here.
|
I'm Bonk, and I've done a quick review of your PR. This PR adds a
Otherwise the change is clean and well-scoped. The helper is straightforward, the three call sites are correctly wired up, and the |
create-cloudflare
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-pool-workers
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
workers-devprod
left a comment
There was a problem hiding this comment.
Codeowners reviews satisfied
977e531 to
0d90ea8
Compare
|
✅ All changesets look good |
|
Force-pushed to rebase onto current
|
|
Update on the rebased CI run ( Good news on the actual browser-run tests: All 21 tests in Remaining CI blocker: All three packages-and-tools jobs still fail on Opened #13973 to fix the broken test by pointing it at |
When the local Browser Run binding failed to reach an upstream — for example when Chrome failed to launch and miniflare's loopback `/browser/launch` endpoint returned a 500 with a stack-trace text body — the binding worker would call `response.json()` on the non-JSON body and throw an opaque `SyntaxError: Unexpected token X, "..." is not valid JSON`. The actual upstream error message (e.g. `Chrome readiness probe at ... timed out after 5000ms`) was discarded. Add a `parseJsonResponse` helper to the binding worker that reads the body as text first, surfaces the HTTP status and (truncated) body content in the thrown error, and chains the original `SyntaxError` via `cause` when the body was a 2xx response that didn't parse as JSON. Wire it into the three loopback JSON-parsing sites in the binding worker (`/browser/launch`, `/browser/sessionIds`, and per-DO session-info reads). This makes both local-dev failures and CI test flakes self-diagnosing without requiring a debugger.
0d90ea8 to
bb6eb87
Compare
Browser Run tests in `packages/miniflare/test/plugins/browser/index.spec.ts` and the `fixtures/browser-run` fixture call into `@puppeteer/browsers` to ensure Chrome is downloaded into the global Wrangler cache. Every CI run currently re-downloads ~150 MB of Chrome from scratch because the cache directory is per-runner-instance and not shared between runs. Add an `actions/cache@v4` step keyed on the OS + the Chrome version hardcoded in `packages/miniflare/src/index.ts` (`126.0.6478.182")`, restoring/saving `~/.cache/.wrangler/chrome` (Linux), `~/Library/Caches/.wrangler/chrome` (macOS), and `~/AppData/Local/xdg.cache/.wrangler/chrome` (Windows). Benefits: - Cuts ~150 MB and the associated download time off cold CI runs. - Reduces the surface area for the intermittent partial-extraction race that surfaces as `The browser folder (...) exists but the executable (...) is missing` (see #13971 for the diagnostic that exposed this, #13980 for the in-process recovery layer). When the cache is warm and the binary is already extracted, this race can't fire at all because `install()` short-circuits. The cache step runs for the `packages-and-tools` suite on all three OSes and for the `fixtures` suite on macOS + Windows (the Browser Run fixture is excluded on Ubuntu because of AppArmor). When the Chrome version in `packages/miniflare/src/index.ts` changes, the cache key here needs to be bumped manually. A miss only triggers a fresh download — no functional impact.
No specific issue — this is a developer-experience improvement motivated by a recurring CI flake in
Tests (Windows, packages-and-tools)where the underlying error from the local Browser Run binding is hidden behind an opaqueSyntaxError.What
When the local Browser Run binding fails to reach an upstream — for example when Chrome fails to launch and miniflare's loopback
/browser/launchendpoint returns a 500 with a stack-trace text body — the binding worker callsresponse.json()on the non-JSON body and throws a cryptic:The actual upstream error message (e.g.
Chrome readiness probe at ... timed out after 5000msfrom the recently-addedwaitForBrowserReadyprobe) is discarded by.json()before the SyntaxError is thrown. This makes both local-dev failures and CI flakes nearly impossible to diagnose from logs alone.How
Add a
parseJsonResponse<T>(resp, context)helper tobinding.worker.tsthat:!resp.ok, throwsError("${context}: upstream returned ${status} ${statusText}\n${truncatedBody}").JSON.parse(text). If it throws, rethrows with the same shape plus the originalSyntaxErrorchained viacause.... (truncated, N bytes total)suffix to avoid overwhelming CI logs.Wire it into the three loopback JSON-parsing sites in the binding worker:
BrowserRenderingRouter.#acquireSession()—/browser/launch(the Chrome-failed-to-launch path).BrowserRenderingRouter.#getActiveSessions()—/browser/sessionIds.The internal
setSessionInfoRoutereq.json()(line 172) is left alone — input is always JSON from#acquireSession()itself.Test plan
pnpm -F miniflare test:ci test/plugins/browser/index.spec.ts✅pnpm -F miniflare check:type✅pnpm check:lint✅pnpm check:format✅validate-changesets.ts✅No new tests added — the helper is exercised by the existing passing tests on the happy path, and the failure path only matters when an upstream is broken (which is the diagnostic case we're improving, not a behavior we want to assert).
What this looks like after the next CI flake
Before:
After:
…which immediately tells us whether bumping
waitForBrowserReady's 5s timeout is the right next fix, or whether something else is going on.