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
- Fix the flagged names in a follow-up bulk rename: non-empty, same URL kind, no invalid bytes
- Inspect the failed list printed after the run to see exactly which pair failed and why it was skipped
- 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
- Keep edited names non-empty and free of NUL/control bytes
- Never change the line count when editing the bulk-rename buffer
- For exotic names, use single-file rename to see the underlying strand error
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.