Closed general

Black screen at launch: mixed-build frontend assets — shell inits __sveltekit_1jo40ag but chunks read __sveltekit_1hz8szf, boot import chain rejects, kit.start never runs

kaleymer · 23d ago ·closed by Colby Knox

Hydrogen boots to a fully black window on Kale's box (build 7bb7c99e-dirty, built Sep 29 3:11 PM, exe C:/Users/Kale/AppData/Local/Adom Hydrogen/hydrogen.exe). The backend is healthy the whole time — control API answers on :47084, heartbeats tick, the workspace/code-server reports editor_will_load: true — but the client area renders nothing. This is NOT the fullscreen/minimize presentation bug from issue #1585: the present-kick passes from that fix ran and re-presented the webview, and the frame still stayed black, because there is nothing to paint.

Root cause: mixed-build frontend assets — the SvelteKit shell and the JS chunks are from two different builds

The app shell HTML served at tauri.localhost initializes SvelteKit instance id 1jo40ag:

__sveltekit_1jo40ag = { base: "", env: null };
...
import("/_app/env.js").then(({ env }) => {
    __sveltekit_1jo40ag.env = env;
    Promise.all([
        import("/_app/immutable/entry/start.BZRne8Yw.js"),
        import("/_app/immutable/entry/app.CTqrBwpU.js")
    ]).then(([kit, app]) => { kit.start(app, element); });
});

But the _app/immutable assets on disk are from a DIFFERENT build whose instance id is 1hz8szf. The very first line of the shared chunk reads:

// /_app/immutable/chunks/index.DKNlELYB.js, char 1
const env = globalThis.__sveltekit_1hz8szf.env;

__sveltekit_1hz8szf is never defined (the shell defined __sveltekit_1jo40ag), so the chunk throws on import, the whole dynamic-import chain rejects, kit.start() never runs, and the window stays black forever. Confirmed in the log at boot:

13:53:58.175 [JS UNHANDLED REJECTION] TypeError: Cannot read properties of undefined (reading 'env')
    at http://tauri.localhost/_app/immutable/chunks/index.DKNlELYB.js:1:42
13:53:58.176 [JS UNHANDLED REJECTION] TypeError: Cannot read properties of undefined (reading 'env')
    at http://tauri.localhost/_app/immutable/chunks/index.DKNlELYB.js:1:42

Live DOM probe over /eval confirms the app never mounted: document.readyState == "complete" but document.body.innerHTML is 525 chars — just the unhydrated bootstrap <div style="display: contents"> + the inline script above. entry.BuxsNU1k.js (imported by start.BZRne8Yw.js) also references only __sveltekit_1hz8szf, so the entry files and chunks agree with each other; it is the SHELL that is from a different build than the entire _app tree.

How it likely happened

The running exe is a dirty local build (build_dirty: true, 7bb7c99e...-dirty-1790712682). The shell HTML Tauri serves and the _app asset tree it serves come from different pnpm build outputs — i.e. a rebuild raced or partially overwrote the frontend output (stale build/ dir not cleaned between builds, or the exe was relinked against a frontend dir that a later/earlier build had partially replaced). Content-hashed chunk filenames make the two builds interleave silently instead of 404ing.

Suggested fixes

  1. Immediate (this box): a clean frontend rebuild (rm -rf .svelte-kit build && pnpm build) then hd_ship, or simply applying the already-staged 1.0.501 installer (Update 1.0.501 staged + verified in the log) replaces the whole asset tree atomically and should clear it.
  2. Build pipeline: make the frontend build step clean its output dir before emitting, so shell + assets can never interleave across builds (this is exactly the frontend flavor of the relinkOnly stale-build trap hd_ship already guards the Rust side against).
  3. Robustness: the shell's bootstrap import(...) chain has no .catch. A top-level catch that paints a visible error screen ("frontend failed to load: ") would turn a silent black window into a diagnosable one — the backend was perfectly healthy and could even have reported it via the existing log channel and a reload button.

Environment

  • Hydrogen 1.0.500 (insiders), running SHA 7bb7c99e51a281b1ef7859c75c30ac3b5772a3fa-dirty-1790712682, pid 27448
  • Windows, WebView2; workspace distro Adom-Workspace healthy; ab embedded (LaunchFlag)
  • /_app/version.json = 1790712406135; /_app/env.js loads fine (carbon/iron URLs)

Diagnosed remotely over the bridge: hd_status → hd_shot (pure black client area) → hd_log → /eval DOM + asset probes.

4 Replies

Colby Knox · 23d ago

Confirmed, and thank you: this is the right diagnosis. 1.0.500 was built on Colby-ROG2, and the build host tells the story your instance ids do. A release build started against a stale VERSION, I killed it and restarted, and the two pnpm build runs overlapped (the killed build still produced its installer at 15:12:36, the 1.0.500 installer landed at 15:14:15). Content-hashed chunk names let the two outputs interleave in build/, tauri embedded the mix, and the shell's __sveltekit_1jo40ag never matched the chunks' 1hz8szf. I verified the fix on a separate clean release exe rather than on the installer's exe, so the mix was never seen before it shipped.

Your observation that the present-kick ran at boot also matters: it was armed by a zero-size Resized at startup, which is why that build toggled every webview's visibility on launch. That kick is gone.

What is done:

  • Public rolled back to 1.0.492 at 20:58Z.
  • 1.0.502 building now: only the fullscreen-plus-maximized normalization remains for #92, nothing touches webview visibility or bounds, and it only arms on a state tao reports as minimized.
  • scripts/build-release.sh now wipes build/ and .svelte-kit/output before the build and refuses to ship when the exe or build/ carries more than one __sveltekit_<id> (main 7aa516ec). Your suggestion 2, in the release script rather than the hd_ship verb.
  • The shipped installer's exe gets the same id check before publish from now on.

For your box: 1.0.501 (John's, staged) or 1.0.502 once it is on insiders both replace the asset tree whole and should clear it; a clean rm -rf .svelte-kit build && pnpm build plus hd_ship also works. I will post here when 1.0.502 is up.

kaleymer · 23d ago

Confirmed: applying the staged 1.0.501 installer (POST /updater/install) on the affected box replaced the frontend asset tree atomically and the UI renders normally again after relaunch — full shell, VS Code pane, Claude panel, and webview tabs all painting. The black screen was purely the mixed-build boot crash. Suggested fixes 2 (clean the frontend output dir on every build) and 3 (a .catch on the shell bootstrap import chain that paints a visible error screen) are still open.

Colby Knox · 23d ago

Thanks for confirming. Status: suggestion 2 is on main (7aa516ec, build-release.sh wipes build/ and .svelte-kit/output first and refuses to ship when the tree carries more than one _sveltekit id); 1.0.502 is on insiders (a single-id tree, verified before publish) with the #92 fix and none of the visibility kick. Suggestion 3, a visible boot-failure screen when the shell's import chain rejects, is next and rides the following release; I will close this when it ships.

Colby Knox · 22d ago

Both open suggestions are shipped, public since 1.0.505 (current public 1.0.513): the release build wipes the frontend output first and refuses an installer whose frontend carries more than one SvelteKit id (suggestion 2), and a start whose import chain fails reloads once and then paints a readable error instead of a black window (suggestion 3). Closing. Thanks for the diagnosis.

Log in to reply.