sxyazi/yazi · warning · anyhow::Error

Invalid new or old file name

Error message

Invalid new or old file name

What it means

In bulk rename, each old/new pair is rebuilt into a full URL via replace_url, which does url.try_replace(take, PathDyn::with(url.kind(), rep)). If the edited name from the temp file cannot be turned into a valid dynamic path for that entry's URL kind, the pair is pushed to failed with "Invalid new or old file name" and skipped; the rest of the batch proceeds.

Source

Thrown at yazi-actor/src/mgr/bulk_rename.rs:121

		}

		let (old, new) = old.into_iter().zip(new).filter(|(o, n)| o != n).unzip();
		let todo = Self::prioritized_paths(old, new);
		if todo.is_empty() {
			return Ok(());
		}

		if !Self::ask_continue(&todo, decision)? {
			return Ok(());
		}

		let permit = WATCHER.acquire().await.unwrap();
		let (mut failed, mut succeeded) = (Vec::new(), HashMap::with_capacity(todo.len()));
		for (o, n) in todo {
			let (Ok(old), Ok(new)) =
				(Self::replace_url(&selected[o.0], root, &o), Self::replace_url(&selected[n.0], root, &n))
			else {
				failed.push((o, n, anyhow!("Invalid new or old file name")));
				continue;
			};

			if maybe_exists(&new).await && !engine::must_identical(&old, &new).await {
				failed.push((o, n, anyhow!("Destination already exists")));
			} else if let Err(e) = engine::rename(&old, &new).await {
				failed.push((o, n, e.into()));
			} else if let Ok(f) = engine::file(new).await {
				succeeded.insert(old, f);
			} else {
				failed.push((o, n, anyhow!("Failed to retrieve file info")));
			}
		}

		if !succeeded.is_empty() {
			let it = succeeded.iter().map(|(o, n)| (o.as_url(), n.url.as_url()));
			log_if_err!(Pubsub::pub_after_bulk_rename(it));
			FilesOp::rename(succeeded);

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Fix the flagged names in a follow-up bulk rename: non-empty, same URL kind, no invalid bytes
  2. Inspect the failed list printed after the run to see exactly which pair failed and why it was skipped
  3. Rename the problem file individually (normal rename flow) to surface the underlying strand error directly
Defensive patterns

Strategy: validation

Validate before calling

// Drop pairs whose replacement is not a valid dynamic path before renaming:
let todo: Vec<_> = todo.into_iter()
    .filter(|(o, n)| {
        Self::replace_url(&selected[n.0], root, n).is_ok()
            && Self::replace_url(&selected[o.0], root, o).is_ok()
    })
    .collect();

Prevention

When it happens

Trigger: A line in the bulk-rename temp file is empty, contains NUL or bytes invalid for the entry's strand kind, or the replacement cannot be represented as a PathDyn of the same URL kind (e.g. local-style name under an archive:// entry). Either the old or the new name failing triggers this.

Common situations: Hand-editing the buffer and leaving an empty line; scripted rewrites inserting invalid bytes; renaming entries backed by plugin URL kinds with names that kind rejects.

Related errors


AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16). Data as JSON: /api/errors/a926b063b74722b0. Report an issue: GitHub.