Boot fails with "Unable to preload CSS" when main's CSS preload fails; chunk reload guard isn't registered yet#26437
What happened
I created a guest share link in the desktop app and opened it in Firefox on the same Mac to check that it worked. The page showed "T3 Code failed to start" with:
| 1 | Error: Unable to preload CSS for /assets/main-ufMFs_gT.css |
| 2 | P/r</</</<@/assets/index-BBHBqBtb.js:5:6081 |
The same error appeared again on a reload. A load about 25 minutes later worked.
Diagnosis
Why a single failed request ends at the boot error screen. apps/web/src/bootstrap.ts runs import("./main"). The bundler's preload helper in the built entry chunk (index-*.js) first adds a <link rel="stylesheet"> for main-*.css. When that link fires error, the helper dispatches vite:preloadError. Nothing calls preventDefault(), so the helper rethrows. bootstrap.ts catches the error and calls showBootError.
Why the existing auto-reload doesn't help. apps/web/src/main.tsx registers a vite:preloadError listener that calls reloadOnceForChunkLoadError(). The guard's comment says it exists for this case: "one reload fetches the fresh index". But that listener lives in main.tsx, the very module whose preload failed, so it isn't registered yet. showBootError has no special handling for chunk or preload errors either. The result: any failure to load main-*.js or main-*.css goes straight to the boot error screen with no automatic retry. Lazy route chunks are covered by the guard.
What triggered it here. The stylesheet request was lost inside the managed relay client (cloudflared) and never reached the local server:
- Server trace: the server received the
/guestpage request,index-*.js,main-*.jsand about 160 other/assets/*.jsmodules through the relay host, all within about 1 s and all returning 200. There is no request for/assets/main-ufMFs_gT.css. cloudflaredcounters:cloudflared's/metricsshowtotal_requests 433butrequest_errors 6. Its count of responses by status code (221×200, 205×304, 1×403) matches exactly what the server trace recorded on the relay host over the same period (427 requests). So 6 requests failed insidecloudflaredbefore reaching the origin.- Per-request detail is lost:
ManagedEndpointRuntimepassescloudflared's output to the logger at warning level, but none of it lands inserver.trace.ndjson. The 6 failures can't be matched to individual requests after the fact.
Not confirmed: why the reload failed too. A normal reload about 20 minutes later failed again. The server received only /guest, and again no CSS request. Two possible causes, neither confirmed:
- the tunnel failed the CSS request again; or
- the browser reused the failed response.
The relay serves /assets/* with cache-control: max-age=14400, while the local server sends no-cache. That includes the text/html single-page-app fallback page for asset paths that don't exist. A later load that fetched the CSS fresh booted normally.
Suggested direction. Register the vite:preloadError → reloadOnceForChunkLoadError() handler in bootstrap.ts before import("./main"). Alternatively, have showBootError do the one-time reload for preload and dynamic-import errors. Separately, persisting cloudflared request errors to the trace would make relay failures visible.
No commits on main touch bootstrap.ts, main.tsx or chunkReloadGuard.ts after v0.1.3.
Steps to reproduce
The failure here was transient:
- On desktop app 0.1.3 with T3 Connect (managed relay) enabled, create a guest share link.
- Open it in Firefox. The first, cold load sends about 160 parallel module requests through the relay.
- If the
main-*.cssrequest fails in the tunnel, the boot error screen appears and no automatic reload happens.
To hit the boot-error path deterministically, which should work but was not run during triage: open the web app with the main-*.css request blocked, for example with Firefox DevTools → Network → right-click the request → Block URL, then reload. Expected: one automatic reload, as for lazy chunks. Actual (from reading the code): "T3 Code failed to start" straight away.
Version
0.1.3 (desktop app, stable channel; web UI served by that app's server through the T3 Connect relay)
Environment
macOS 27.0 (Apple Silicon), Firefox 158; desktop app 0.1.3 with managed cloudflared 2026.10.4. Triage CLI 0.1.3.
Evidence
| 1 | # Boot error screen |
| 2 | Error: Unable to preload CSS for /assets/main-ufMFs_gT.css |
| 3 | P/r</</</<@/assets/index-BBHBqBtb.js:5:6081 |
| 4 | Version: 0.1.3 / Channel: stable / Surface: web / Time: 2026-10-28T11:03:32.060Z |
| 5 | |
| 6 | # server.trace.ndjson, requests on prod-<redacted>.t3coderelay.com (Firefox UA), UTC |
| 7 | 11:03:31.425 GET /guest 200 |
| 8 | 11:03:31.734 GET /assets/index-BBHBqBtb.js 200 |
| 9 | 11:03:31.916 GET /assets/main-lZWM_z1N.js 200 (1112 ms) |
| 10 | ... ~160 more GET /assets/*.js 200 |
| 11 | # no GET /assets/main-ufMFs_gT.css |
| 12 | |
| 13 | # later normal reload: only the page reached the server |
| 14 | 11:24:52.282 GET /guest 200 |
| 15 | # load that worked: CSS fetched, guest route chunks followed |
| 16 | 11:28:13.039 GET /assets/main-ufMFs_gT.css 304 |
| 17 | 11:28:14.298 GET /assets/guest-Tvhdc8S4.js 304 |
| 18 | |
| 19 | # cloudflared /metrics (relay client up since 10:45) |
| 20 | cloudflared_tunnel_total_requests 433 |
| 21 | cloudflared_tunnel_request_errors 6 |
| 22 | cloudflared_tunnel_response_by_code{status_code="200"} 221 |
| 23 | cloudflared_tunnel_response_by_code{status_code="304"} 205 |
| 24 | cloudflared_tunnel_response_by_code{status_code="403"} 1 |
| 25 | # server trace, same host and window: 427 requests (200: 221, 304: 205, 403: 1) |
| 26 | |
| 27 | # relay vs local headers for /assets/* |
| 28 | relay GET /assets/main-ufMFs_gT.css -> 200 text/css, cache-control: max-age=14400 |
| 29 | relay GET /assets/does-not-exist.css -> 200 text/html, cache-control: max-age=14400 |
| 30 | local GET /assets/main-ufMFs_gT.css -> 200 text/css, cache-control: no-cache |
Related issues
#10613 shows the same failure type (a code bundle that fails to load ends at the error screen) but has a different trigger and surface: a desktop channel switch, a route chunk over t3code://. Here it is the main chunk's CSS on the web surface over the relay, a case the reload guard can't reach because its listener lives in main.tsx.
Fix applied or workaround
Nothing was changed on the machine; a later load fetched the CSS and booted normally. If it recurs, a hard reload (Cmd+Shift+R) forces a fresh fetch of the assets.
Filed by
Claude Opus 5.5 (claude-opus-5-5) in Claude Code, via t3 triage
I'm seeing something similar, I'm have t3code exposed through Google Cloud IAP TCP forwarding, its configured with 128 threads, loading t3code pops it, requests fail and i get the boot failure screen for some js file or other.
As a workaround i was able to set throttling in dev tools to good 2g which slows it down enough.