sxyazi/yazi · error · io::Error
trash item is not a directory
Error message
trash item is not a directory
What it means
`Trash::list(Some(entry))` (yazi-fs/src/trash/freedesktop/trash.rs:22) lists the children of a trashed directory by reading `entry.backing`. Only directory entries can be listed; passing a trashed regular file yields `ErrorKind::InvalidInput`, `trash item is not a directory`. The code carries a `// TODO`, acknowledging directory-descent into trash items is incomplete.
Source
Thrown at yazi-fs/src/trash/freedesktop/trash.rs:22
use yazi_macro::ok_or_not_found;
use yazi_shim::Twox128;
use super::{super::{TrashCha, TrashEntries, TrashEntry, TrashId, restore_item}, TrashInfo};
use crate::{cha::{Cha, ChaSig}, file::File};
pub struct Trash;
impl Trash {
pub(crate) fn new() -> io::Result<Self> { Ok(Self) }
pub(crate) fn list(&self, entry: Option<&TrashEntry>) -> io::Result<Vec<TrashEntry>> {
let Some(entry) = entry else {
return self.tops();
};
// TODO
if !entry.lcha.is_dir() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "trash item is not a directory"));
}
fs::read_dir(&entry.backing)?
.map(|dent| {
let dent = dent?;
entry.child(dent.file_name())
})
.collect()
}
pub(crate) fn entry(&self, id: &TrashId) -> io::Result<TrashEntry> {
let info = TrashInfo::parse(id.top())?;
if !os_limited::trash_folders()
.map_err(io::Error::other)?
.iter()
.any(|folder| folder == &info.root)
{
return Err(io::Error::new(io::ErrorKind::NotFound, "trash item outside of trash folders"));View on GitHub (pinned to 94abcfa92f)
Solutions
- Check `entry.lcha.is_dir()` before calling `list(Some(&entry))`; for files use `entry`/`metadata` or restore/remove instead.
- In UI code, make file-type trash entries non-navigable.
- Call `list(None)` to get top-level trash items only.
Example fix
// before
let children = trash.list(Some(&entry))?; // Err if entry is a file
// after
if entry.lcha.is_dir() {
let children = trash.list(Some(&entry))?;
} else {
// open/restore/remove the file instead of listing it
} Defensive patterns
Strategy: type-guard
Validate before calling
if entry.lcha.is_dir() {
let children = trash.list(Some(&entry))?;
} else {
// a file: open/restore it, or show its metadata only
} Type guard
fn is_listable_trash_entry(entry: &TrashEntry) -> bool {
entry.lcha.is_dir()
} Try / catch
match trash.list(Some(&entry)) {
Ok(children) => { /* ... */ }
Err(e) if e.kind() == io::ErrorKind::InvalidInput => { /* entry is a file: not navigable */ }
Err(e) => return Err(e),
} Prevention
- Gate 'enter/navigate' actions in the trash browser on `lcha.is_dir()`.
- Use `list(None)` for the top level and only descend into entries you verified are directories.
- Remember directory-descent inside trash is marked TODO upstream; keep expectations minimal.
When it happens
Trigger: Navigating into a trash item in the trash browser: pressing enter/`read_dir` on an entry whose `lcha` says it is a file, or calling `list()` with a file entry instead of `None` (tops).
Common situations: Selecting a trashed file (not folder) and issuing an open/enter action that maps to listing; scripts that call list on every entry uniformly.
Related errors
- trash item outside of trash folders
- invalid trash info path
- Unsupported OS for trash operation
- restore target already exists: {to:?}
- invalid trash item path
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/8e74d7b09259f5e9.
Report an issue: GitHub.