sxyazi/yazi · error · io::Error
Cannot write cache stamp: {e}
Error message
Cannot write cache stamp: {e} What it means
Raised by Stamp::write when persisting a cache-stamp file fails. A stamp is a small file under the URL's auth stamp root (<tmp>/yazi-<uid>/<kind>_<scheme>_<domainhash>/%stamp/<urlhash>) that stores a 26-byte content signature plus the target filename, so yazi can later detect that a remote (non-local) file changed. The original std::io::Error from Local::regular(&path).write(data) is re-wrapped with io::Error::new(e.kind(), ...), so the kind (PermissionDenied, StorageFull, NotFound, ...) is preserved and the {e} suffix carries the real cause.
Source
Thrown at yazi-vfs/src/stamp.rs:61
let stamp = Self::read_at(&path).await?;
let name = StrandCow::with(dir.kind(), stamp.name()).map_err(io::Error::other)?;
let url = dir.try_join(name)?;
if url.hash_u128_str(&mut [0; Self::SIG_LEN]).as_bytes() != key.encoded_bytes() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "Cache stamp does not match entry"));
}
Ok(url)
}
pub async fn write(cha: Cha, url: Url<'_>) -> io::Result<()> {
let path = url.stamp_entry().ok_or_else(|| io::Error::other("Cannot determine cache stamp"))?;
let data = Self::encode(cha, url)?;
Local::regular(&path)
.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"));
}
View on GitHub (pinned to 94abcfa92f)
Solutions
- Read the wrapped {e} and e.kind() (preserved by the wrap) to get the true cause before changing anything
- Verify the temp dir: make $TMPDIR/$XDG_RUNTIME_DIR an existing writable absolute path, and recreate <tmp>/yazi-<uid> if a cleaner removed it
- Free space on the filesystem that hosts the temp dir (StorageFull) and retry the fetch so the stamp is rewritten
- Clear the %stamp subtree for that auth so damaged entries get rebuilt from scratch
- As a library user, treat a failed stamp write as non-fatal: the cached file itself is intact, only change-detection metadata is missing
Example fix
// before
Stamp::write(cha, url.as_url()).await?; // aborts the whole fetch pipeline on a temp-dir hiccup
// after
if let Err(e) = Stamp::write(cha, url.as_url()).await {
// stamp is only invalidation metadata; keep the cached file and continue
tracing::warn!("stamp write failed ({e}); change detection disabled for {url}");
} Defensive patterns
Strategy: try-catch
Validate before calling
if let Some(stamp) = url.as_url().stamp_entry() {
if let Some(parent) = stamp.parent() {
std::fs::create_dir_all(parent)?; // surfaces PermissionDenied / StorageFull before the download
}
} Try / catch
match Stamp::write(cha, url.as_url()).await {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
// temp dir or stamp file unwritable: fix TMPDIR / recreate <tmp>/yazi-<uid>, then retry once
}
Err(e) => tracing::warn!("stamp write failed: {e}"), // non-fatal: only invalidation metadata is lost
} Prevention
- Point TMPDIR/XDG_RUNTIME_DIR at a writable directory that tmp cleaners do not purge mid-session
- Treat stamp-write failures as warnings; the cached file stays usable, only change detection is lost
- Run create_dir_all on the stamp parent before starting downloads when you drive yazi-vfs yourself
When it happens
Trigger: Awaiting Stamp::write(cha, url) for a non-local URL (SFTP, Mount, Hub, Scope) whose stamp_entry() resolves, and the underlying write fails: the yazi temp dir was deleted mid-session, $TMPDIR/$XDG_RUNTIME_DIR is unwritable or missing, the temp filesystem is full (ENOSPC), or the process lacks permission on an existing stamp file.
Common situations: Long-running session whose /tmp was purged by tmpreaper/systemd-tmpfiles; TMPDIR pointed at a nonexistent or read-only path in a container; disk full on the tmpfs; embedding yazi-vfs in a service with a restricted temp directory.
Related errors
- Not a local URL: {url:?}
- Invalid cache stamp
- Destination already exists
- restore target already exists: {to:?}
- trash item has no put-back location
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/1539abca2e228f8f.
Report an issue: GitHub.