atuinsh/atuin · error

Atuin running with no parent!

Error message

Atuin running with no parent!

What it means

Shell::current() identifies the invoking shell by asking sysinfo for the parent of the current process. sysinfo's Process::parent() returns Option<Pid> and yields None when the OS reports no parent (ppid 0). Atuin assumes it was launched by a shell and turns a missing parent into a panic via expect("Atuin running with no parent!"). Callers include atuin-dotfiles shell detection (crates/atuin-dotfiles/src/shell.rs:120) and atuin-ai commands (crates/atuin-ai/src/commands.rs:73).

Source

Thrown at crates/atuin-common/src/shell.rs:45

#[derive(Debug, Error, Serialize)]
pub enum ShellError {
    #[error("shell not supported")]
    NotSupported,

    #[error("failed to execute shell command: {0}")]
    ExecError(String),
}

impl Shell {
    pub fn current() -> Shell {
        let sys = System::new_all();

        let process = sys
            .process(get_current_pid().expect("Failed to get current PID"))
            .expect("Process with current pid does not exist");

        let parent = sys
            .process(process.parent().expect("Atuin running with no parent!"))
            .expect("Process with parent pid does not exist");

        let shell = parent.name().trim().to_lowercase();
        let shell = shell.strip_prefix('-').unwrap_or(&shell);

        Shell::from_string(shell.to_string())
    }

    pub fn from_env() -> Shell {
        std::env::var("ATUIN_SHELL").map_or(Shell::Unknown, |shell| {
            Shell::from_string(shell.trim().to_lowercase())
        })
    }

    pub fn config_file(&self) -> Option<std::path::PathBuf> {
        let mut path = directories::BaseDirs::new()?.home_dir().to_owned();

        // TODO: handle all shells

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Run atuin from a shell or under an init so it has a parent: ENTRYPOINT ["/bin/sh", "-c", "atuin <cmd>"] or docker run --init
  2. Set ATUIN_SHELL (bash/zsh/fish/xonsh/nu) in the environment and use env-based detection paths (Shell::from_env) instead of parent detection
  3. If embedding atuin-common, call Shell::from_env() or resolve the parent with sysinfo yourself and degrade gracefully instead of Shell::current()

Example fix

// before (Dockerfile)
ENTRYPOINT ["atuin", "daemon"]

// after — atuin keeps a parent process
ENTRYPOINT ["/bin/sh", "-c", "atuin daemon"]
Defensive patterns

Strategy: validation

Validate before calling

fn has_parent_shell() -> bool {
    let sys = sysinfo::System::new_all();
    sysinfo::get_current_pid()
        .ok()
        .and_then(|pid| sys.process(pid))
        .and_then(|p| p.parent())
        .and_then(|ppid| sys.process(ppid))
        .is_some()
}

if !has_parent_shell() {
    eprintln!("atuin has no parent shell; set ATUIN_SHELL or run under a shell");
    std::process::exit(2);
}

Try / catch

let shell = std::panic::catch_unwind(atuin_common::shell::Shell::current)
    .unwrap_or_else(|_| {
        std::env::var("ATUIN_SHELL")
            .map(|s| atuin_common::shell::Shell::from_string(s.to_lowercase()))
            .unwrap_or(atuin_common::shell::Shell::Unknown)
    });

Prevention

When it happens

Trigger: Any command that reaches Shell::current() while the atuin process has ppid 0 — i.e. atuin itself is PID 1: a container ENTRYPOINT that execs the atuin binary directly, or an init/supervisor that replaces itself with atuin.

Common situations: Docker/Podman images with ENTRYPOINT ["atuin", ...] so atuin becomes PID 1; minimal VM appliances where init execs into atuin; debug shells that run the bare binary with no parent.

Related errors


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