atuinsh/atuin · critical

failed to execute script

Error message

failed to execute script

What it means

`execute_script` in the scripts command launches a script via `execute_script_interactive` and `.expect("failed to execute script")`s if the child process (shebang interpreter) cannot be spawned or its pty session cannot be set up. This is a panic, not a handled error, meaning the interpreter binary referenced by the shebang is missing/unavailable or the pty allocation failed.

Solutions

  1. Install the interpreter named in the script's shebang (e.g. `apt install zsh`).
  2. Fix the script's shebang line to point to an available interpreter (`#!/usr/bin/env bash`).
  3. Verify the interpreter path exists: `which <interpreter>` or `command -v <interpreter>` before running.

Example fix

// before (stored script content)
#!/usr/bin/env zsh
echo hello
// after
#!/usr/bin/env bash
echo hello
Defensive patterns

Strategy: validation

Validate before calling

# verify the shebang interpreter exists before executing a stored script
interp=$(head -n1 script.sh | sed 's|^#!||; s|.*env ||')
command -v "$interp" >/dev/null || { echo "interpreter '$interp' not installed"; exit 1; }

Prevention

When it happens

Trigger: Running a stored atuin script whose shebang names an interpreter not present on PATH (e.g. `#!/usr/bin/env zsh` with zsh absent), or when `execute_script_interactive` fails to allocate the pty/spawn the process at crates/atuin/src/command/client/scripts.rs:158.

Common situations: Syncing scripts between machines where the shebang interpreter exists on one host but not another; running scripts in minimal containers lacking bash/zsh/python; bad shebang lines saved into the script store.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/236c8db6b7d41301. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin/src/command/client/scripts.rs:158

        let (command, args) = parts.split_first().ok_or_eyre("No editor command found")?;

        let status = std::process::Command::new(command).args(args).arg(&path).status()?;
        if !status.success() {
            bail!("failed to open editor");
        }

        // Read back the edited content
        let content = std::fs::read_to_string(&path)?;
        path.close()?;

        Ok(content)
    }

    // Helper function to execute a script and manage stdin/stdout/stderr
    async fn execute_script(script_content: String, shebang: String) -> Result<i32> {
        let mut session = execute_script_interactive(script_content, shebang)
            .await
            .expect("failed to execute script");

        // Create a channel to signal when the process exits
        let (exit_tx, mut exit_rx) = tokio::sync::oneshot::channel();

        // Set up a task to read from stdin and forward to the script
        let sender = session.stdin_tx.clone();
        let stdin_task = tokio::spawn(async move {
            use tokio::io::AsyncReadExt;
            use tokio::select;

            let stdin = tokio::io::stdin();
            let mut reader = tokio::io::BufReader::new(stdin);
            let mut buffer = vec![0u8; 1024]; // Read in chunks for efficiency

            loop {
                // Use select to either read from stdin or detect when the process exits
                select! {
                    // Check if the script process has exited

View on GitHub (pinned to 900007c480)