atuinsh/atuin · error

failed to execute script

Error message

failed to execute script

What it means

`atuin scripts run` writes the script to a temp file and executes it via execute_script_interactive (crates/atuin-scripts/src/execution.rs): first directly, then through the shebang interpreter as fallback. That helper returns Err when spawning fails — interpreter missing, ENOEXEC/EACCES (noexec /tmp), temp file creation failure, EMFILE — and execute_script immediately expects the Result, panicking with 'failed to execute script'.

Source

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

            .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 202f6ad98e)

Solutions

  1. Verify the shebang interpreter exists (command -v python3) and fix the script's shebang via atuin scripts edit
  2. If /tmp is noexec, remount exec or point TMPDIR at an exec-mounted filesystem
  3. Inspect the stored script with `atuin scripts get <name> --script` to confirm its shebang and interpreter path

Example fix

# before — shebang names an interpreter absent on this host
#!/usr/bin/env python3

# after — use an interpreter present locally
#!/usr/bin/env bash
Defensive patterns

Strategy: validation

Validate before calling

fn interpreter_available(shebang: &str) -> bool {
    let Some(bin) = shebang
        .trim_start_matches("#!")
        .trim()
        .split_whitespace()
        .next()
    else {
        return false;
    };
    std::process::Command::new(bin).output().is_ok()
}

assert!(interpreter_available(&script.shebang), "shebang interpreter is not installed");

Try / catch

// in a fork: propagate instead of panicking
let session = execute_script_interactive(script_content, shebang)
    .await
    .map_err(|e| eyre::eyre!("failed to execute script: {e}"))?;

Prevention

When it happens

Trigger: Running `atuin scripts run <name>` when the shebang interpreter does not exist locally (#!/usr/bin/env python3 without python3), /tmp is mounted noexec so direct execution fails and the interpreter fallback also fails, or the process lacks resources to spawn a child.

Common situations: Scripts synced from another machine naming an interpreter absent on this host; hardened containers with noexec TMPDIR; minimal images without bash or env.

Related errors


AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16). Data as JSON: /api/errors/236c8db6b7d41301. Report an issue: GitHub.