2026, Jan 09 15:00

Stop 'No such file or directory' errors: use uvx to run Marimo from a single-file Python shebang

Getting 'Failed to spawn: marimo' with uv run? Learn why the shebang fails and how using uvx (uv tool run) installs deps and launches a Marimo notebook.

Shipping a single Python file that bootstraps its own environment and launches a Marimo notebook sounds ideal, especially when you want painless distribution. But a subtle choice of command in the shebang can derail the whole flow with a terse error about a missing executable.

Minimal example that fails

The following script aims to install dependencies into the uv cache and then start Marimo in edit mode. It looks tidy, yet it errors out at runtime.

#!/usr/bin/env -S uv run -- marimo edit main.py
# /// script
# requires-python = >=3.12
# dependencies = [
#     "marimo",
#     "numpy",
#     "matplotlib",
# ]
# ///
import marimo
nb = marimo.App()
@nb.cell
def c1():
    import marimo as m
    return m
@nb.cell
def c2():
    m.md("## Hello, Marimo!")
    return

At launch, it produces the following:

error: Failed to spawn: `marimo`
  Caused by: No such file or directory (os error 2)

What is actually going wrong

The failure happens before your Python code even runs. There is no executable named marimo available at the moment the shebang is executed, so the attempt to spawn that command fails. The reason is tied to the role of the subcommand you chose. The mode you’re using, uv run, executes a command or a script inside an automatically discovered environment. In this context, marimo is neither in PATH nor exposed as a registered project entry point, so there’s nothing to spawn and the process errors out.

The fix: treat Marimo as a tool

Marimo should be invoked as a tool. Instead of uv run, use uvx (or uv tool run), which is designed to resolve and run tools. With that change, the shebang will correctly locate and execute the marimo command.

#!/usr/bin/env -S uvx marimo edit main.py
# /// script
# requires-python = >=3.12
# dependencies = [
#     "marimo",
#     "numpy",
#     "matplotlib",
# ]
# ///
import marimo
nb = marimo.App()
@nb.cell
def c1():
    import marimo as m
    return m
@nb.cell
def c2():
    m.md("## Hello, Marimo!")
    return

Why this subtlety matters

If you want a single-file entry point that “just runs,” the shebang must point to a mode that can discover and execute the intended command. Using the wrong subcommand guarantees a spawn-time failure, because there is no marimo binary available at that point. Choosing uvx ensures the tool is resolved and callable, which unlocks the distribution simplicity you were aiming for.

Takeaways

When the goal is to execute a command like marimo from a self-contained script, pick the tool-oriented invocation. uvx (or uv tool run) resolves and runs the tool, preventing the “No such file or directory” error and allowing your script to install dependencies and launch the notebook as intended.