atuinsh/atuin · error

default socket path always has a parent

Error message

default socket path always has a parent

What it means

`create_default_dir_if_needed` takes the parent of the default socket path and asserts via `.expect("default socket path always has a parent")` that a parent exists. Default socket paths are built as `<dir>/<file>` so a parent always exists; the panic would only fire if the path were a bare root or malformed. Note this only applies to the default variant — user-specified config paths are the user's responsibility.

Solutions

  1. Check how the default socket path is built and ensure it includes a directory component
  2. In tests, construct `SocketPath::Default` with an absolute path like /tmp/atuin.sock rather than a bare filename
  3. Replace the expect with a guard returning SecureTempDirError if defensive behavior is desired

Example fix

// before
let dir = path.parent().expect("default socket path always has a parent");
// after
let Some(dir) = path.parent() else { return Ok(()); };
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_default_socket_path(p: &Path) -> bool { p.parent().is_some() && p.file_name().is_some() }

Prevention

When it happens

Trigger: Calling `create_default_dir_if_needed` on a `SocketPath::Default` whose inner path has no parent (e.g. the path was constructed as just a filename or root "/").

Common situations: Practically unreachable with shipped defaults; can surface if the default socket path construction changes, or if tests construct `SocketPath::Default` from a bare relative filename.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at crates/atuin-client/src/settings/daemon.rs:230

#[cfg(unix)]
pub enum SocketPath<'a> {
    /// A socket path that the user has manually configured in config.toml.
    UserDefined(&'a Path),
    /// The default socket path, used when the path is not manually set in config.toml.
    Default(PathBuf),
}

#[cfg(unix)]
impl<'a> SocketPath<'a> {
    /// Create the default socket directory if needed.
    ///
    /// This only applies to the default socket path: the directory holding a user-specified path
    /// from config.toml is the user's to create, and `$XDG_RUNTIME_DIR` is created for us.
    pub fn create_default_dir_if_needed(&self) -> Result<(), SecureTempDirError> {
        let Self::Default(path) = self else {
            return Ok(());
        };
        let dir = path.parent().expect("default socket path always has a parent");
        create_secure_temp_dir(dir)?;
        Ok(())
    }

    #[must_use]
    pub fn as_path(&self) -> &Path {
        match self {
            Self::UserDefined(path) => path,
            Self::Default(path) => path,
        }
    }

    #[must_use]
    pub fn into_cow(self) -> Cow<'a, Path> {
        match self {
            Self::UserDefined(path) => path.into(),
            Self::Default(path) => path.into(),
        }

View on GitHub (pinned to 900007c480)