#10881·marimo

`marimo edit`: first cell run hangs 30–100s — kernel startup blocks synchronously in `webbrowser.get()` → `xdg-settings` → `xprop -root` (flaky WSLg X server)

Author: kaiserslyCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

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-ready arrives fast; the delay is kernel-side: the cell-op output timestamp equals the moment the kernel finally processes the run. The kernel's control queue just sits on the run request.

  • faulthandler dumps (SIGUSR1 registered via a sitecustomize.py so 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_kernel
    

    The next dump in the sequence shows it progressed to webbrowser.py:447 register_X_browsers → shutil.which, i.e. the xdg-settings subprocess took ~45 s to finish.

  • ps sampling shows the hung grandchild: xdg-settings.

  • Tracing it manually: bash -x xdg-settings get default-web-browser hangs on xprop -root _DT_SAVE_MODE. Direct timing of xprop -root against 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 (first webbrowser.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 edit and uv run marimo edit in a project venv)
  • Python 3.14.2
  • Linux x86_64 inside WSL2 with WSLg: DISPLAY=:0, WAYLAND_DISPLAY=wayland-0

Code to reproduce

  1. uvx marimo edit
  2. Create a new notebook, type print("ok"), hit Shift+Enter
  3. Output takes tens of seconds to appear; run the cell again → instant