sxyazi/yazi · error
Invalid path
Error message
Invalid path
What it means
During bulk creation, each entry's path is joined onto the current working directory with try_join. If the join fails (e.g. an absolute path or a path that cannot be merged), the entry is recorded as failed with "Invalid path" instead of aborting the whole batch. It is a per-entry validation error inside r#do.
Solutions
- Pass relative paths (relative to the current directory) in the bulk_create entries.
- Strip leading slashes or normalize the path before submitting the entry.
- Resolve the desired absolute path yourself and use a different API if absolute targets are required.
Example fix
// before
{ path: "/tmp/target/new-dir", is_dir: true }
// after
{ path: "new-dir", is_dir: true } Defensive patterns
Strategy: validation
Validate before calling
-- Lua, before calling bulk_create local function is_relative(p) return type(p) == "string" and p ~= "" and p:sub(1, 1) ~= "/" end assert(is_relative(entry.path), "bulk_create requires paths relative to cwd")
Prevention
- Strip leading separators from user-provided paths before creating entries.
- Treat entry.path as relative to the cwd by contract.
- Validate all entries up front before invoking bulk_create.
When it happens
Trigger: bulk_create entry whose `path` is absolute (starts with `/`) or otherwise cannot be joined onto `cwd` by try_join.
Common situations: Plugin passing absolute paths to bulk create; user input containing a leading slash; paths with components that fail the join constraints.
Related errors
- invalid trash info path
- invalid trash item path
- Paths must be both absolute or both relative
- URL path kind does not match Auth kind
- at least one of `url` or `mime` must be specified
AI-assisted analysis of sxyazi/yazi@5f901b886b (2026-09-02).
Data as JSON: /api/errors/9413d15e9a1fa743.
Report an issue: GitHub.
Appendix: source
Thrown at yazi-actor/src/mgr/bulk_create.rs:74
});
succ!()
}
}
impl BulkCreate {
async fn r#do(cwd: UrlBuf, todo: Vec<Entry<'_>>) -> Result<()> {
writef!(TTY.writer(), "{}\n", EraseDisplay::All)?;
if todo.is_empty() {
return Ok(());
} else if !Self::ask_continue(&todo, None)? {
return Ok(()); // TODO: support `bulk_exit`?
}
let _permit = WATCHER.acquire().await.unwrap();
let (mut failed, mut succeeded) = (vec![], Vec::with_capacity(todo.len()));
for entry in todo {
let Ok(dist) = cwd.try_join(entry.path) else {
failed.push((entry, anyhow!("Invalid path")));
continue;
};
let result: io::Result<()> = if entry.is_dir {
engine::create_dir_all(&dist).await
} else if let Some(parent) = dist.parent() {
engine::create_dir_all(parent).await.ok();
engine::create_new(&dist).await.map(|_| ())
} else {
Err(io::Error::other("No parent directory"))
};
if let Err(e) = result {
failed.push((entry, e.into()));
} else if let Ok(f) = engine::file(dist).await {
succeeded.push(f);
} else {
failed.push((entry, anyhow!("Failed to retrieve file info")));View on GitHub (pinned to 5f901b886b)