{"record":{"id":"861dd70a18f24e70","repo":"clockworklabs/SpacetimeDB","slug":"failed-to-open-file-for-fsync","errorCode":null,"errorMessage":"failed to open file {} for fsync: {}","messagePattern":"failed to open file (.+?) for fsync: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/snapshot/src/lib.rs","lineNumber":1648,"sourceCode":"                    io::Error::new(\n                        e.kind(),\n                        format!(\"failed to open directory {} for fsync: {}\", path.display(), e),\n                    )\n                })?\n                .sync_all()\n                .map_err(|e| io::Error::new(e.kind(), format!(\"failed to fsync directory {}: {}\", path.display(), e))),\n            Self::File(path) => {\n                File::options()\n                    .read(true)\n                    // Windows needs the file to be writable for `sync_all` to work.\n                    // Set all the open options explicitly, just for visibility.\n                    .write(true)\n                    .truncate(false)\n                    .create(false)\n                    .append(false)\n                    .open(path)\n                    .map_err(|e| {\n                        io::Error::new(\n                            e.kind(),\n                            format!(\"failed to open file {} for fsync: {}\", path.display(), e),\n                        )\n                    })?\n                    .sync_all()\n                    .map_err(|e| io::Error::new(e.kind(), format!(\"failed to fsync file {}: {}\", path.display(), e)))\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::fs::OpenOptions;\n\n    use tempfile::tempdir;\n\n    use super::*;","sourceCodeStart":1630,"sourceCodeEnd":1666,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/crates/snapshot/src/lib.rs#L1630-L1666","documentation":"For Self::File(path), crates/snapshot's sync_all opens the file with explicit options (read+write, no truncate/create/append — write access is required because Windows needs it for sync_all). If the open fails, the underlying kind is preserved and the error is wrapped as 'failed to open file {path} for fsync: {source}'. The file is expected to already exist; the sync helper never creates it.","triggerScenarios":"Syncing a snapshot file that was deleted or moved before the sync ran (NotFound); insufficient permissions to open read-write (PermissionDenied); on Windows, read-only attributes or sharing violations; a race where another process holds an exclusive lock.","commonSituations":"Concurrent cleanup or antivirus scanning removing/locking snapshot files on Windows; file written by a different user/umask so the snapshot process cannot open it writable; orchestration code syncing a path that was never written due to an earlier silent skip.","solutions":["Verify the file exists and check its permissions before syncing; re-run the snapshot write if it was never created","On Windows, clear read-only attributes / coordinate with scanners; open with appropriate sharing","Fix umask/ownership so snapshot files are read-write for the syncing process","Match ErrorKind::NotFound to distinguish 'nothing to sync' from real I/O failure"],"exampleFix":"// before\nSyncTarget::File(&file).sync_all()?; // NotFound: file already GC'd\n\n// after\nif !file.is_file() {\n    anyhow::bail!(\"snapshot file {} vanished before fsync\", file.display());\n}\nstd::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o644))?; // if umask was the issue\nSyncTarget::File(&file).sync_all()?;","handlingStrategy":"validation","validationCode":"if !file.is_file() {\n    anyhow::bail!(\"cannot fsync {}: not present\", file.display());\n}\n#[cfg(unix)]\nstd::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o644))?;","typeGuard":"fn is_syncable_file(p: &Path) -> bool { p.is_file() }","tryCatchPattern":"if let Err(e) = SyncTarget::File(&file).sync_all() {\n    if e.kind() == std::io::ErrorKind::NotFound { /* vanished: re-run snapshot write or skip */ }\n    else if e.kind() == std::io::ErrorKind::PermissionDenied { /* ownership/umask: fix and retry once */ }\n    else { return Err(e); }\n}","preventionTips":["Write snapshot files with permissive-enough umask for the syncing process","On Windows, account for AV/scanners holding handles exclusively","Verify file presence right before the sync step in recovery flows"],"tags":["filesystem","fsync","durability","rust","snapshot","spacetimedb"],"backgroundTag":"fsync-failed","analyzedSha":"9e0d92412ff2248f401a8ad12d535f2b5ac30912","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}