sxyazi/yazi · error · io::Error
invalid trash entry path
Error message
invalid trash entry path
What it means
Returned by TrashId::new when rel is relative but contains parent components ('..'), which would let an id escape its trashed top-level item. This is an anti-traversal invariant enforced at id-construction time with io::ErrorKind::InvalidInput.
Source
Thrown at yazi-fs/src/trash/trash_id.rs:26
pub(crate) struct TrashId {
top: PathBuf,
rel: PathBuf,
}
impl TrashId {
pub(super) fn new<T, R>(top: T, rel: R) -> io::Result<Self>
where
T: Into<PathBuf>,
R: Into<PathBuf>,
{
let top = top.into();
let rel = rel.into();
if top.as_os_str().is_empty() || !rel.is_relative() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry"));
}
if rel.has_parent_component() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry path"));
}
Ok(Self { top, rel })
}
pub(super) fn top(&self) -> &Path { &self.top }
pub(super) fn rel(&self) -> &Path { &self.rel }
#[cfg(target_os = "macos")]
pub(super) fn path(&self) -> PathBuf {
if self.has_rel() { self.top.join(&self.rel) } else { self.top.clone() }
}
pub(super) fn child(&self, name: &OsStr) -> io::Result<Self> {
let rel = self.rel.join(name);
if !rel.is_relative() || rel.has_parent_component() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry path"));View on GitHub (pinned to 94abcfa92f)
Solutions
- Reject or sanitize rel components equal to '..' before constructing the id.
- Use only names returned by Trash:list (real file names cannot be '..').
- Keep rel built exclusively by joining entry.child() results.
Example fix
-- Lua: before
local rel = user_input -- could be "../.."
local e = ya.fs("trash"):entry({ top = top, rel = rel })
-- after
local rel = user_input:gsub("[^/]+", function(s) return s == ".." and "" or s end):gsub("/+", "/")
local e = ya.fs("trash"):entry({ top = top, rel = rel }) Defensive patterns
Strategy: validation
Validate before calling
-- Lua: strip parent components from rel
local function sanitize_rel(rel)
local parts = {}
for seg in rel:gmatch("[^/]+") do
if seg ~= ".." and seg ~= "." then table.insert(parts, seg) end
end
return table.concat(parts, "/")
end Type guard
local function is_safe_rel(rel)
for seg in rel:gmatch("[^/]+") do if seg == ".." then return false end end
return rel:sub(1, 1) ~= "/"
end Try / catch
if not is_safe_rel(id.rel) then id.rel = sanitize_rel(id.rel) end
local e = ya.fs("trash"):entry(id) Prevention
- Treat rel built from user input as untrusted; filter '..' segments.
- Build rel only by joining names returned from list().
- Prefer entry.child-derived ids (the library maintains the invariant for you).
When it happens
Trigger: rel = '../evil', rel = 'a/../../b', or any segment equal to '..' in the Lua table passed to Trash:entry.
Common situations: Plugins building rel by joining untrusted name strings; path normalization logic that leaves '..' segments; user input pasted into a trash navigation command.
Related errors
- invalid trash entry
- invalid trash entry path
- invalid trash put-back name
- item is not in the trash
- invalid trash item path
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/a0375eed363df0da.
Report an issue: GitHub.