sxyazi/yazi · error

Missing filename

Error message

Missing filename

What it means

The Unix casefold implementation needs both the parent directory and the file name component to statat() the exact name. If the path has no parent (bare relative name) or no file_name (trailing slash / '.' / '..'), it returns 'Missing filename'.

Solutions

  1. Ensure the path passed to final_name points to an actual file, not a directory or root
  2. Strip trailing separators before calling
  3. Canonicalize the path first so components are well-formed

Example fix

// before
Casefold::final_name(Path::new("/"))?
// after
if path.file_name().is_none() { return Err(...); }
Casefold::final_name(path)?
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn split_parent_name(path: &Path) -> Option<(&Path, &std::ffi::OsStr)> {
    path.parent().zip(path.file_name())
}

Try / catch

match Casefold::final_name(path) {
    Ok(n) => n,
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => return path.as_os_str().to_owned(),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling Casefold::final_name with a path like '/', './', 'foo/', or a bare 'file' that has no parent component.

Common situations: Passing root or directory URLs with trailing separators into the casefold lookup; constructing paths programmatically that lost their file component.

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 sxyazi/yazi@a541adde4e (2026-09-18). Data as JSON: /api/errors/0db92e804c710b2a. Report an issue: GitHub.

Appendix: source

Thrown at yazi-fs/src/casefold/unix.rs:13

use std::{ffi::{OsStr, OsString}, io::{self, ErrorKind}, os::{fd::AsFd, unix::ffi::OsStrExt}, path::Path};

use rustix::fs::{AtFlags, FileType, Mode, OFlags, Stat, open, statat};

use super::Casefold;
use crate::scanner::Scanner;

impl Casefold {
	pub(super) fn final_name(path: &Path) -> io::Result<OsString> {
		let (parent, name) = path
			.parent()
			.zip(path.file_name())
			.ok_or_else(|| io::Error::new(ErrorKind::InvalidInput, "Missing filename"))?;

		let parent = if parent.as_os_str().is_empty() { Path::new(".") } else { parent };
		let fd = open(parent, OFlags::RDONLY | OFlags::DIRECTORY | OFlags::CLOEXEC, Mode::empty())?;
		let meta = statat(&fd, name, AtFlags::SYMLINK_NOFOLLOW)?;

		if Self::case_sensitive(&fd) == Some(true) {
			Ok(name.to_owned())
		} else if Self::is_same_mount(&fd, name) {
			Self::scan_fast(name, &fd, meta)
		} else {
			Self::scan_full(name, &fd, meta)
		}
	}

	fn scan_fast(name: &OsStr, fd: &impl AsFd, stat: Stat) -> io::Result<OsString> {
		let mut names = vec![];
		Scanner::visit(&fd, |n, ino| {
			let n = OsStr::from_bytes(n.to_bytes());

View on GitHub (pinned to a541adde4e)