{"record":{"id":"44a4001a74a8f632","repo":"clockworklabs/SpacetimeDB","slug":"error-syncing-data-to-disk","errorCode":null,"errorMessage":"error syncing data to disk","messagePattern":"error syncing data to disk","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/core/src/database_logger.rs","lineNumber":518,"sourceCode":"        // If following isn't requested, we can stream the data.\n        if !follow {\n            return self.logger.lock().await.tail_stream(n);\n        }\n        match n {\n            // If we don't need to access the disk,\n            // locking and spawning can be avoided.\n            None | Some(0) => self.subscribe().map(Ok).boxed(),\n\n            // Otherwise, we need to hold the lock to prevent writes\n            // while we gather a snapshot of the persistent tail.\n            Some(n) => {\n                // Cap reading the tail into memory at a few hundred KiB.\n                let n = n.min(2500);\n                let (tail, more) = {\n                    let inner = self.logger.clone().lock_owned().await;\n                    let more = self.subscribe();\n                    asyncify(move || {\n                        inner.sync_data().expect(\"error syncing data to disk\");\n                        (inner.tail(n), more)\n                    })\n                }\n                .await;\n\n                stream::once(future::ready(tail)).chain(more.map(Ok)).boxed()\n            }\n        }\n    }\n\n    fn subscribe(&self) -> impl Stream<Item = Bytes> + use<T> {\n        BroadcastStream::new(self.broadcast.subscribe()).filter_map(move |x| {\n            future::ready(match x {\n                Ok(chunk) => Some(chunk),\n                Err(BroadcastStreamRecvError::Lagged(skipped)) => {\n                    log::trace!(\"skipped {skipped} lines in module log\");\n                    None\n                }","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/core/src/database_logger.rs#L500-L536","documentation":"When `DatabaseLogger::tail` is asked for the last `n` lines, it takes the file lock and — inside a blocking thread — calls `sync_data().expect(\"error syncing data to disk\")` so the snapshot is durable before streaming. This expect fires when the OS rejects the fsync on the log file: disk full, I/O error, or the file living on a failed/unplugged filesystem.","triggerScenarios":"Subscribing with `tail(n, follow)` where n > 0 (e.g. `spacetime logs` or the HTTP log endpoint) while the log file's volume returns an fsync error such as ENOSPC or EIO.","commonSituations":"Operators tailing a database's logs when the node's disk has filled or the device is failing; log directory on a network mount with broken fsync semantics.","solutions":["Free or grow space on the volume holding the database's log files.","Check dmesg/journalctl for hardware or filesystem errors; run fsck if corruption is suspected.","Retry the tail request after remediation; the log file itself may be incomplete.","Keep log/data volumes on healthy local storage."],"exampleFix":"// before\ninner.sync_data().expect(\"error syncing data to disk\");\n\n// after: stream the (possibly not-yet-durable) tail rather than aborting\nif let Err(e) = inner.sync_data() {\n    log::warn!(\"tail: fsync failed, streaming unsynced tail: {}\", e);\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Monitor disk space on the node's data/log directory.","Tail with n = 0 (subscribe-only) when a durable snapshot isn't required — that path skips the fsync entirely.","Keep log volumes on healthy local storage."],"tags":["rust","spacetimedb","logging","fsync","disk-io"],"backgroundTag":"disk-fsync-failure","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}