`marimo edit`: first cell run hangs 30–100s — kernel startup blocks synchronously in `webbrowser.get()` → `xdg-settings` → `xprop -root` (flaky WSLg X server)
Describe the bug
Disclaimer: I used GLM-5.3-flash to debug this problem.
On WSL2 (WSLg), running uvx marimo edit, opening a notebook and running a trivial cell (print("ok")) takes 30–100 seconds before the output is displayed. Subsequent runs in the same session are instant (~1s), but every new notebook / reopened notebook pays the cost again.
Measured headlessly (Playwright-driven Chromium, fresh notebook each time, same server):
| run | time to output |
|---|---|
| 1 | 30.5 s |
| 2 | 39.1 s |
| 3 | 48.2 s |
| 4 | 68.3 s |
| 5 | 72.3 s |
| 6 | 81.9 s |
| 7 | 83.9 s |
| 8 | 91.4 s |
| 9 | 101.0 s |
| subsequent runs (same kernel) | 0.1–1.4 s |
Analysis (evidence)
WebSocket frames (captured from the browser) show the frontend sends the run request immediately,
kernel-readyarrives fast; the delay is kernel-side: thecell-opoutput timestamp equals the moment the kernel finally processes the run. The kernel's control queue just sits on the run request.faulthandlerdumps (SIGUSR1 registered via asitecustomize.pyso spawned kernel children dump all thread stacks) show the kernel main thread blocked for the entire slow window in:subprocess.py:1207 communicate subprocess.py:556 run subprocess.py:472 check_output webbrowser.py:525 register_standard_browsers webbrowser.py:45 get marimo/_runtime/patches.py:40 patch_webbrowser marimo/_runtime/runtime.py:654 Kernel.__init__ marimo/_runtime/kernel_lifecycle.py:174 create_kernelThe next dump in the sequence shows it progressed to
webbrowser.py:447 register_X_browsers → shutil.which, i.e. thexdg-settingssubprocess took ~45 s to finish.pssampling shows the hung grandchild:xdg-settings.Tracing it manually:
bash -x xdg-settings get default-web-browserhangs onxprop -root _DT_SAVE_MODE. Direct timing ofxprop -rootagainst the WSLg X server on this machine: 0 s, 0 s, 20.7 s, 31 s, 40 s+ (timeout) — WSLg's X server intermittently stalls X client connections, which matches the 30–100 s distribution.
So the full chain is:
user hits Run
→ server spawns a fresh kernel process (multiprocessing spawn) for the instantiation
→ Kernel.__init__ calls patches.patch_webbrowser() → webbrowser.get()
→ CPython webbrowser.register_standard_browsers() (runs once per process)
→ subprocess.check_output(["xdg-settings", "get", "default-web-browser"]) # no timeout
→ dbus-send / xprop -root
→ WSLg X server hangs intermittently (20–40+ s per call)
→ run command waits in the kernel's control queue all that time
→ output finally appears
Red herring: the frontend logs Language server initialization failed RPCError: Request "initialize" timed out after 30000ms (copilot/pylsp) during slow runs, but those same errors occur in fast runs too and do not gate output rendering (fast runs render output in 0.1–0.8 s despite them).
Why "first run only"
Each notebook instantiation spawns a new kernel process, which re-runs patch_webbrowser() → webbrowser.get() → the OS browser detection lottery. Once the kernel is up, runs are instant.
Workarounds (validated)
env -u DISPLAY -u WAYLAND_DISPLAY uvx marimo edit→ 6/6 first runs at 0.1 s (browser auto-open disabled, marimo prints the URL instead)DISPLAY=:99 uvx marimo edit→ 4/4 first runs at 0.3–0.8 s (X connection fails fast instead of hanging)
Suggested fix
Don't block kernel startup on webbrowser.get():
- call
patch_webbrowser()lazily (firstwebbrowser.open()), and/or - perform the browser-detection call in a background thread / wrap it in a timeout, and/or
- skip the eager
webbrowser.get()probe and register marimo's fallback browser unconditionally.
Any of these would make first runs fast regardless of a flaky X server (WSLg, remote desktops, broken X sessions).
Will you submit a PR?
- Yes
Environment
- marimo 0.24.2 (repro'd both with
uvx marimo editanduv run marimo editin a project venv) - Python 3.14.2
- Linux x86_64 inside WSL2 with WSLg:
DISPLAY=:0,WAYLAND_DISPLAY=wayland-0
Code to reproduce
uvx marimo edit- Create a new notebook, type
print("ok"), hit Shift+Enter - Output takes tens of seconds to appear; run the cell again → instant
Source: marimo-team/marimo