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 shellsView on GitHub (pinned to 202f6ad98e)
Solutions
- Run atuin from a shell or under an init so it has a parent: ENTRYPOINT ["/bin/sh", "-c", "atuin <cmd>"] or docker run --init
- Set ATUIN_SHELL (bash/zsh/fish/xonsh/nu) in the environment and use env-based detection paths (Shell::from_env) instead of parent detection
- 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
- Never run the atuin binary directly as PID 1 (container ENTRYPOINT); wrap it in a shell or an init supervisor
- Export ATUIN_SHELL in headless and containerized environments so shell detection does not depend on the process tree
- In containers, prefer docker run --init or tini so every process keeps a parent
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
- Failed to get current PID
- bug in list query. please report
- bug in search query. please report
- issue in stats previous query
- issue in stats next query
AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16).
Data as JSON: /api/errors/247d83272d177b95.
Report an issue: GitHub.