sxyazi/yazi · warning · io::Error

Cache stamp does not match target

Error message

Cache stamp does not match target

What it means

Returned by Stamp::validate with ErrorKind::InvalidData when the filename stored inside the stamp does not equal the encoded name of the URL being validated. Stamp files are keyed by a u128 hash of the URL, and the payload repeats the target filename; a mismatch means the stamp found at that key belongs to a different target, so the cached data cannot be trusted for this URL.

Source

Thrown at yazi-vfs/src/stamp.rs:77

			.write(data)
			.await
			.map_err(|e| io::Error::new(e.kind(), format!("Cannot write cache stamp: {e}")))
	}

	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]
	pub fn name(&self) -> &[u8] { &self.0[Self::SIG_LEN..] }
}

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Treat this InvalidData as a cache miss: delete the cached entry plus its stamp and re-download the file
  2. Clear the yazi temp stamp tree (<tmp>/yazi-<uid>/*/%stamp) after upgrading yazi so stale formats disappear
  3. Check you are validating the exact URL the stamp was read from (same auth, scheme, domain); validating against a renamed variant always fails
  4. If it reproduces on fresh URLs with no upgrade involved, collect the URL and stamp bytes and report a hashing-collision bug upstream

Example fix

// before
stamp.validate(cha, url.as_url())?; // InvalidData bubbles up and kills the peek

// after
match stamp.validate(cha, url.as_url()) {
    Ok(()) => use_cached(url).await,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => refetch(url).await, // stale stamp => cache miss
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: fallback

Validate before calling

// cheap pre-check mirroring validate()'s name comparison (SIG_LEN = 26 bytes)
if let Some(name) = url.as_url().name() {
    if stamp.name() != name.encoded_bytes() {
        // skip validate(); go straight to the re-download path
    }
}

Try / catch

match stamp.validate(cha, url.as_url()) {
    Ok(()) => use_cached(url).await,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => refetch(url).await, // mismatch => cache miss
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling stamp.validate(cha, url) where stamp was read from url.stamp_entry() but stamp.name() != url.name().encoded_bytes(): a hash collision in the %stamp directory, a stamp left over after the remote file was renamed/moved, a stamp written by a different yazi version whose URL hashing differed, or temp-dir files copied around by hand.

Common situations: Upgrading yazi across versions that changed URL hashing while old stamp files remain in <tmp>/yazi-<uid>/.../%stamp; leftover stamps after renames on the remote side; manually restoring or copying yazi temp directories between machines.

Related errors


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