sxyazi/yazi · error · io::Error
InvalidInput
InvalidInput
Error message
trash item is not a directory
What it means
In the Windows trash backend, `list()` with a parent `TrashEntry` enumerates its children in the recycle-bin folder. This error is returned when the parent entry's cached attributes (`lcha`) indicate it is not a directory, or is an indirect/link item, so it cannot have children to enumerate. It is a caller-contract violation: `list(Some(entry))` must be given a directory trash item.
Source
Thrown at yazi-fs/src/trash/windows/trash.rs:28
static COM: io::Result<Com> = Com::new();
}
pub struct Trash;
impl Trash {
pub(crate) fn new() -> io::Result<Self> {
COM.with(|result| {
result.as_ref().map(|_| Self).map_err(|e| io::Error::new(e.kind(), e.to_string()))
})
}
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() || entry.lcha.is_indirect() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "trash item is not a directory"));
}
let original = entry.original.as_deref().ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "trash item has no put-back location")
})?;
self
.resolve(entry)?
.children()?
.into_iter()
.map(|item| {
let name = item.display_name(SIGDN_PARENTRELATIVEPARSING)?;
item.entry(entry.id.child(&name)?, Some(original.join(&name)))
})
.collect()
}
pub(crate) fn entry(&self, id: &TrashId) -> io::Result<TrashEntry> {View on GitHub (pinned to 5f901b886b)
Solutions
- Check `entry.lcha.is_dir() && !entry.lcha.is_indirect()` before calling list with a parent entry.
- Only pass directory entries to the child enumeration path; list files as leaves.
- Re-fetch the entry's metadata if the cached lcha may be stale.
- Treat the error as InvalidInput and skip non-directory entries during traversal.
Example fix
// before
let children = trash.list(Some(&entry))?;
// after
if entry.lcha.is_dir() && !entry.lcha.is_indirect() {
let children = trash.list(Some(&entry))?;
} else {
// leaf entry: no children
} Defensive patterns
Strategy: validation
Validate before calling
if !(entry.lcha.is_dir() && !entry.lcha.is_indirect()) {
return Ok(()); // leaf: no children to list
}
let children = trash.list(Some(&entry))?; Type guard
fn is_listable_dir(entry: &TrashEntry) -> bool {
entry.lcha.is_dir() && !entry.lcha.is_indirect()
} Try / catch
match trash.list(Some(&entry)) {
Ok(children) => children,
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => Vec::new(),
Err(e) => return Err(e.into()),
} Prevention
- Check is_dir/is_indirect before child enumeration.
- Treat non-directory trash items as leaves.
- Refresh cached attributes if entries may be stale.
When it happens
Trigger: Calling `Trash::list(Some(entry))` where `entry.lcha` is not a dir or `is_indirect()` is true — e.g. passing a trashed file instead of a trashed folder, or a shortcut/indirect item.
Common situations: Building a tree view of the recycle bin and feeding non-directory entries into the child-listing call; stale attribute caches after the entry changed.
Related errors
AI-assisted analysis of sxyazi/yazi@5f901b886b (2026-09-02).
Data as JSON: /api/errors/839c93c685257457.
Report an issue: GitHub.