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

  1. Pass relative paths (relative to the current directory) in the bulk_create entries.
  2. Strip leading slashes or normalize the path before submitting the entry.
  3. 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

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


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)