astrid-runtime/astrid · error

private atomic file has no parent

Error message

private atomic file has no parent: {}

What it means

atomic_write_private_file_unix writes a private file by creating a 0600 temporary in the target's parent directory and renaming it into place. It throws this when path.parent() returns None (root/empty path), since there is no parent directory in which to stage the temporary file.

Solutions

  1. Pass a full path including parent directory and file name, not "/".
  2. Fix the configuration or variable supplying the output path.
  3. Join the directory and file explicitly: parent.join("filename").
  4. Validate with `path.parent().is_some() && path.file_name().is_some()` before calling.

Example fix

// before
atomic_write_private_file(Path::new("/"), b"data")?;
// after
atomic_write_private_file(&Path::new("/home/me/.astrid").join("credentials"), b"data")?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_writable_atomic_target(path: &std::path::Path) -> bool {
    path.parent().is_some() && path.file_name().is_some()
}

Try / catch

match atomic_write_private_file(path, bytes) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => eprintln!("bad target path: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling atomic_write_private_file with a path such as "/" or a path with no parent component, before it attempts ensure_private_directory on the parent.

Common situations: Misconfigured output path holding a mount root; path-building code that produced an empty/root path; forgetting to join the file name to the directory.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/2905f0d9b1fc47ca. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-core/src/platform_fs.rs:660

        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("private file has no name: {}", path.display()),
        )
    })?;
    let directory = open_directory_no_follow_unix(parent)?;
    let flags = OFlag::O_RDONLY | OFlag::O_NOFOLLOW | OFlag::O_CLOEXEC;
    openat(&directory, name, flags, Mode::from_bits_truncate(0o600))
        .map(std::fs::File::from)
        .map_err(nix_io_error)
}

#[cfg(unix)]
fn atomic_write_private_file_unix(path: &Path, bytes: &[u8]) -> io::Result<()> {
    use std::io::Write as _;
    use std::os::unix::fs::OpenOptionsExt as _;

    let parent = path.parent().ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("private atomic file has no parent: {}", path.display()),
        )
    })?;
    ensure_private_directory(parent)?;
    let temporary = parent.join(format!(".astrid-private-{}", uuid::Uuid::new_v4().simple()));
    let write = (|| {
        let mut file = std::fs::OpenOptions::new()
            .write(true)
            .create_new(true)
            .mode(0o600)
            .open(&temporary)?;
        file.write_all(bytes)?;
        file.sync_all()
    })();
    if let Err(error) = write {
        let _ = std::fs::remove_file(&temporary);
        return Err(error);

View on GitHub (pinned to affd8760f4)