astrid-runtime/astrid · error
private file has no name
Error message
private file has no name: {} What it means
Alongside a parent, open_file_no_follow_unix requires a final file name component to perform the openat call. It throws this when path.file_name() returns None — paths that end in "..", ".", or are root — because there is no concrete file to open.
Solutions
- Pass the exact file path, not a directory or a path ending in ".." or ".".
- Normalize the path before calling (e.g. path.canonicalize() then append the file name).
- Add a caller-side check: `path.file_name().is_some()` before invoking the API.
- Fix any string-concatenation code that appends separators or ".." fragments.
Example fix
// before
restrict_private_file(Path::new("/home/me/.astrid/.."))?;
// after
restrict_private_file(Path::new("/home/me/.astrid/credentials"))?; Defensive patterns
Strategy: validation
Validate before calling
fn names_a_file(path: &std::path::Path) -> bool {
path.file_name().is_some()
&& !matches!(path.components().next_back(), Some(std::path::Component::ParentDir) | Some(std::path::Component::CurDir))
} Type guard
fn has_file_name(path: &std::path::Path) -> bool { path.file_name().is_some() } Try / catch
if path.file_name().is_none() {
return Err(anyhow!("path must end in a file name: {}", path.display()));
}
validate_private_file(path)?; Prevention
- Avoid paths ending in ".." or "."
- Canonicalize computed paths before passing them
- Do not pass a directory where a file path is required
When it happens
Trigger: Calling restrict_private_file or validate_private_file with a path ending in "..", ".", or a root path, so file_name() yields None.
Common situations: Joining or normalizing logic that produced "dir/.."; a caller passing the parent directory instead of the file; paths built by string concatenation ending with a trailing separator that normalizes to ".".
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
- private atomic file has no parent
- private file has no parent
- Astrid volume is not a regular file
- cannot resolve install directory for
- capsule source is neither a directory nor a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c9261503ea045260.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-core/src/platform_fs.rs:642
Ok(path.to_path_buf())
} else {
Ok(std::env::current_dir()?.join(path))
}
}
#[cfg(unix)]
fn open_file_no_follow_unix(path: &Path) -> io::Result<std::fs::File> {
use nix::fcntl::{OFlag, openat};
use nix::sys::stat::Mode;
let parent = path.parent().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("private file has no parent: {}", path.display()),
)
})?;
let name = path.file_name().ok_or_else(|| {
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(View on GitHub (pinned to affd8760f4)