sxyazi/yazi · error
trash item is not a directory
Error message
trash item is not a directory
What it means
The freedesktop Trash::list lists the children of a trashed directory entry. Because listing children of a regular file is meaningless (and marked TODO in the source), it rejects non-directory entries up-front with InvalidInput "trash item is not a directory". Only trashed directories can be expanded into child entries.
Solutions
- Check entry.lcha.is_dir() (or the entry's kind) before calling list(); skip files or emit them as leaves.
- Use the flat trash listing (tops()) and handle files and directories differently in the caller.
- Catch io::ErrorKind::InvalidInput from list() and treat it as an empty children set for file entries.
Example fix
// before
let children = trash.list(&entry).await?;
// after
let children = if entry.lcha.is_dir() {
trash.list(&entry).await?
} else {
vec![] // files have no children
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Rust
if !entry.lcha.is_dir() { return Ok(vec![]); } Type guard
// Rust
fn is_trashed_dir(entry: &TrashEntry) -> bool { entry.lcha.is_dir() } Try / catch
let children = match trash.list(&entry).await {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => Vec::new(), // file entry
other => other?,
}; Prevention
- Check is_dir on the entry before enumerating children.
- Treat trashed files as leaves in tree UIs.
- Refresh trash state after every restore/empty operation.
When it happens
Trigger: Calling list() with a trash entry that points to a trashed file rather than a trashed directory — e.g. asking the trash provider to enumerate children of "cat.jpg".
Common situations: A UI or plugin navigates into a trashed file as if it were a folder; stale UI state shows a deleted file as expandable; code iterates all trash entries and calls list() on each without filtering directories.
Related errors
AI-assisted analysis of sxyazi/yazi@a541adde4e (2026-09-18).
Data as JSON: /api/errors/8e74d7b09259f5e9.
Report an issue: GitHub.
Appendix: source
Thrown at yazi-fs/src/trash/freedesktop/trash.rs:21
use trash::os_limited;
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();
};
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 a541adde4e)