{"record":{"id":"1539abca2e228f8f","repo":"sxyazi/yazi","slug":"cannot-write-cache-stamp-e","errorCode":null,"errorMessage":"Cannot write cache stamp: {e}","messagePattern":"Cannot write cache stamp: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-vfs/src/stamp.rs","lineNumber":61,"sourceCode":"\t\tlet stamp = Self::read_at(&path).await?;\n\t\tlet name = StrandCow::with(dir.kind(), stamp.name()).map_err(io::Error::other)?;\n\n\t\tlet url = dir.try_join(name)?;\n\t\tif url.hash_u128_str(&mut [0; Self::SIG_LEN]).as_bytes() != key.encoded_bytes() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"Cache stamp does not match entry\"));\n\t\t}\n\n\t\tOk(url)\n\t}\n\n\tpub async fn write(cha: Cha, url: Url<'_>) -> io::Result<()> {\n\t\tlet path = url.stamp_entry().ok_or_else(|| io::Error::other(\"Cannot determine cache stamp\"))?;\n\t\tlet data = Self::encode(cha, url)?;\n\n\t\tLocal::regular(&path)\n\t\t\t.write(data)\n\t\t\t.await\n\t\t\t.map_err(|e| io::Error::new(e.kind(), format!(\"Cannot write cache stamp: {e}\")))\n\t}\n\n\tfn encode(cha: Cha, url: Url) -> io::Result<Vec<u8>> {\n\t\tlet name = url.name().ok_or_else(|| io::Error::other(\"URL has no filename\"))?;\n\n\t\tlet mut buf = Vec::with_capacity(Self::SIG_LEN + name.len());\n\t\tbuf.extend_from_slice(cha.hash_u128_str(&mut [0; Self::SIG_LEN]).as_bytes());\n\t\tbuf.extend_from_slice(name.encoded_bytes());\n\n\t\tOk(buf)\n\t}\n\n\tpub fn validate(&self, cha: Cha, url: Url) -> io::Result<()> {\n\t\tlet name = url.name().ok_or_else(|| io::Error::other(\"URL has no filename\"))?;\n\t\tif self.name() != name.encoded_bytes() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"Cache stamp does not match target\"));\n\t\t}\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-vfs/src/stamp.rs#L43-L79","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nStamp::write(cha, url.as_url()).await?; // aborts the whole fetch pipeline on a temp-dir hiccup\n\n// after\nif let Err(e) = Stamp::write(cha, url.as_url()).await {\n    // stamp is only invalidation metadata; keep the cached file and continue\n    tracing::warn!(\"stamp write failed ({e}); change detection disabled for {url}\");\n}","handlingStrategy":"try-catch","validationCode":"if let Some(stamp) = url.as_url().stamp_entry() {\n    if let Some(parent) = stamp.parent() {\n        std::fs::create_dir_all(parent)?; // surfaces PermissionDenied / StorageFull before the download\n    }\n}","typeGuard":null,"tryCatchPattern":"match Stamp::write(cha, url.as_url()).await {\n    Ok(()) => {}\n    Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {\n        // temp dir or stamp file unwritable: fix TMPDIR / recreate <tmp>/yazi-<uid>, then retry once\n    }\n    Err(e) => tracing::warn!(\"stamp write failed: {e}\"), // non-fatal: only invalidation metadata is lost\n}","preventionTips":["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"],"tags":["io","cache","filesystem","temp-dir"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}