sxyazi/yazi · warning · io::Error
Remote file has changed since last download
Error message
Remote file has changed since last download
What it means
Returned by Stamp::validate when the stored signature (self.sig()) differs from the current Cha's hash_u128_str. The cached data was valid for the target name, but the remote file's metadata/content signature has changed since the stamp was written, so the cache is stale.
Solutions
- Re-download the remote file and rewrite the stamp via Stamp::write with the fresh Cha
- Re-fetch current Cha metadata for the URL before validating to avoid false staleness
- If staleness is acceptable, bypass validation and serve cache with a warning
Example fix
// before
stamp.validate(cha, url)?;
// after
match stamp.validate(cha, url) {
Ok(()) => use_cached(),
Err(e) if e.to_string().contains("changed since last download") => redownload_and_restamp(url).await?,
Err(e) => return Err(e),
} Defensive patterns
Strategy: validation
Validate before calling
let mut sig = [0u8; 16];
let current = cha.hash_u128_str(&mut sig);
if stamp.sig() != current { /* stale: re-download before serving cache */ } Type guard
fn stamp_fresh(stamp: &Stamp, cha: &Cha) -> bool {
let mut buf = [0u8; 16];
stamp.sig() == cha.hash_u128_str(&mut buf)
} Try / catch
match stamp.validate(cha, url) {
Ok(()) => serve_cached(),
Err(e) if e.to_string().contains("changed since last download") => redownload().await?,
Err(e) => return Err(e),
} Prevention
- Re-fetch Cha metadata from the remote before each validation
- Rewrite the stamp whenever the remote file changes
- Expire cache entries older than a freshness threshold
When it happens
Trigger: Calling stamp.validate(cha, url) after the remote file was modified, re-uploaded, or its metadata (size/mtime feeding the Cha hash) changed; also when validating with a Cha fetched at a different time than the stamp was written.
Common situations: Remote file updated on the server between downloads; clock/metadata skew on the remote; using a cached stamp after re-listing the remote directory shows new metadata.
Related errors
- Cache stamp does not match entry
- Cache stamp does not match target
- Cannot parse cache stamp
- Cannot read cache stamp
- Cannot write cache stamp
AI-assisted analysis of sxyazi/yazi@8ebf930f17 (2026-09-02).
Data as JSON: /api/errors/9d5c934e8d2c72ee.
Report an issue: GitHub.
Appendix: source
Thrown at yazi-vfs/src/stamp.rs:81
fn encode(cha: Cha, url: Url) -> io::Result<Vec<u8>> {
let name = url.name().ok_or_else(|| io::Error::other("URL has no filename"))?;
let mut buf = Vec::with_capacity(Self::SIG_LEN + name.len());
buf.extend_from_slice(cha.hash_u128_str(&mut [0; Self::SIG_LEN]).as_bytes());
buf.extend_from_slice(name.encoded_bytes());
Ok(buf)
}
pub fn validate(&self, cha: Cha, url: Url) -> io::Result<()> {
let name = url.name().ok_or_else(|| io::Error::other("URL has no filename"))?;
if self.name() != name.encoded_bytes() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "Cache stamp does not match target"));
}
if self.sig() != cha.hash_u128_str(&mut [0; Self::SIG_LEN]) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Remote file has changed since last download",
));
}
Ok(())
}
#[inline]
pub fn sig(&self) -> &str { unsafe { str::from_utf8_unchecked(&self.0[..Self::SIG_LEN]) } }
#[inline]
fn name(&self) -> &[u8] { &self.0[Self::SIG_LEN..] }
}
impl TryFrom<Vec<u8>> for Stamp {
type Error = io::Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {View on GitHub (pinned to 8ebf930f17)