clockworklabs/SpacetimeDB · error · io::Error
failed to open directory {} for fsync: {}
Error message
failed to open directory {} for fsync: {} What it means
Part of the snapshot crate's durability sync (SyncTarget::sync_all): on Unix, a newly written snapshot file's enclosing directory must also be fsynced so the directory entry itself survives a crash. This variant wraps the failure to File::open the directory path, preserving the original error kind - the directory could not be opened at all.
Source
Thrown at crates/snapshot/src/lib.rs:1581
Dir(&'a Path),
}
impl FileOrDirPath<'_> {
/// `fsync` the file or directory at path `self`.
///
/// On *nix systems, both a file and its enclosing directory should be
/// `fsync`ed to make the file durable.
///
/// On Windows, only the file needs to be synced, and it's even an error to
/// sync a directory. Passing in [Self::Dir] is thus a no-op on Windows.
fn sync_all(&self) -> io::Result<()> {
match self {
#[cfg(target_os = "windows")]
Self::Dir(path) => Ok(()),
#[cfg(not(target_os = "windows"))]
Self::Dir(path) => File::open(path)
.map_err(|e| {
io::Error::new(
e.kind(),
format!("failed to open directory {} for fsync: {}", path.display(), e),
)
})?
.sync_all()
.map_err(|e| io::Error::new(e.kind(), format!("failed to fsync directory {}: {}", path.display(), e))),
Self::File(path) => {
File::options()
.read(true)
// Windows needs the file to be writable for `sync_all` to work.
// Set all the open options explicitly, just for visibility.
.write(true)
.truncate(false)
.create(false)
.append(false)
.open(path)
.map_err(|e| {
io::Error::new(View on GitHub (pinned to 524b4487d9)
Solutions
- Stop concurrent deletion/cleanup jobs that race with snapshot creation.
- Verify the configured snapshot directory exists and is writable before starting.
- Fix permissions on the snapshot root.
- Retry the snapshot once the environment is stable.
Defensive patterns
Strategy: validation
Validate before calling
use std::fs;
fn snapshot_dir_ready(dir: &str) -> std::io::Result<()> {
let md = fs::metadata(dir)?;
if !md.is_dir() {
return Err(std::io::Error::new(std::io::ErrorKind::NotADirectory, dir));
}
Ok(())
} Try / catch
match sync_result {
Err(e) if e.to_string().contains("failed to open directory") => {
// Directory vanished or is not a directory: stop racing cleanup jobs,
// recreate the directory, then retry the snapshot.
}
r => r,
} Prevention
- Do not run snapshot cleanup/GC concurrently with snapshot creation on the same root.
- Verify the snapshot root exists, is a directory, and is writable at startup.
- Alert on permission changes to snapshot volumes.
When it happens
Trigger: Saving/syncing a snapshot when the snapshot directory was deleted or renamed concurrently (cleanup job racing the snapshot); the path exists but is not a directory (ENOTDIR); the process lacks permission on the directory.
Common situations: Concurrent snapshot GC deleting directories while a snapshot is being finalized; snapshot root misconfigured to a file path; permission changes on a shared volume.
Related errors
- failed to fsync directory {}: {}
- failed to open file {} for fsync: {}
- failed to fsync file {}: {}
- AlreadyExists
- repo {}: error getting file metadata for segment {}: {}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/801af999b94def3a.
Report an issue: GitHub.