sxyazi/yazi · error · io::Error
revalidated file URL changed
Error message
revalidated file URL changed
What it means
During directory revalidation, entries are re-stat'ed and compared against the cached `File`; if the fresh entry's URL differs from the cached one, this InvalidData error is thrown. Because a file's URL should be stable across a revalidation (same key/urn in the same folder), a change signals corruption or a broken engine `revalidate` implementation rather than a normal rename (renames go through explicit events, not revalidation).
Source
Thrown at yazi-vfs/src/entries.rs:65
async fn go(entries: &[DirEntry]) -> Vec<File> {
let mut files = Vec::with_capacity(entries.len());
for dent in entries {
files.push(match dent.file().await {
Ok(file) => file,
Err(_) => File::from_dummy(dent.url(), dent.file_type().await.ok()),
});
}
files
}
let (first, second, third) = join!(go(first), go(second), go(third));
Ok([first, second, third].into_iter().flatten().collect())
}
async fn revalidate(old: &File) -> io::Result<Option<File>> {
match engine::revalidate(old).await? {
Some(new) if new.url != old.url => {
Err(io::Error::new(io::ErrorKind::InvalidData, "revalidated file URL changed"))
}
Some(new) if !new.is_dir() => Err(io::ErrorKind::NotADirectory.into()),
Some(new) => Ok(Some(new)),
None if PARTITIONS.read().timeless(old.cha) => Ok(Some(old.clone())),
None => Ok(None),
}
}
}
View on GitHub (pinned to 8ebf930f17)
Solutions
- Fix the engine's revalidate/metadata implementation to return an entry with the identical URL it was queried with
- If the backend canonicalizes names, normalize at the adapter so the URL round-trips unchanged
- Check for symlink-following or case-folding in the backend stat path and disable it for keying
- Catch the error and drop the stale entry (trigger a full directory reload) instead of failing the whole revalidation
Example fix
// before (in a custom engine's revalidate) Ok(Some(File::new(canonical_url, cha))) // url changed -> InvalidData // after Ok(Some(File::new(old.url.clone(), cha))) // preserve queried URL
Defensive patterns
Strategy: try-catch
Validate before calling
// Engines must return the queried URL unchanged; assert at the adapter boundary debug_assert_eq!(new.url, old.url, "engine revalidate changed the URL");
Try / catch
match entries::revalidate(old).await {
Err(e) if e.to_string() == "revalidated file URL changed" => {
// engine bug or name normalization — drop the stale entry and schedule a full reload
log::warn!("revalidate changed URL for {:?}; forcing reload", old.url);
reload_partition(old.url.parent()).await
}
r => r,
} Prevention
- Engine implementations must return a File whose URL equals the one queried — never canonicalize, decode, or resolve symlinks into the URL
- Normalize names in the backend adapter so URLs round-trip identically
- Handle renames via explicit rename events, not by letting revalidate return a different URL
- On this error, fall back to a full directory refresh instead of propagating the failure
When it happens
Trigger: An engine's `revalidate` returns a File whose `url` differs from the input — e.g. a backend normalizing the path differently, changing case, resolving symlinks into the URL, or returning an entry for a different file entirely.
Common situations: Backends that canonicalize or percent-decode the urn during stat, remote servers returning differently-escaped names, or a bug in a custom Lua VFS returning the wrong entry from its metadata/cha hook.
Related errors
- Not a custom VFS URL: {url:?}
- unknown image format
- invalid trash info path
- {e}
- URN cannot be longer than URI
AI-assisted analysis of sxyazi/yazi@8ebf930f17 (2026-09-02).
Data as JSON: /api/errors/512d8a0e492d1463.
Report an issue: GitHub.