{"record":{"id":"b25e9c42d3ade0d6","repo":"clockworklabs/SpacetimeDB","slug":"failed-to-read-bytes-of-commit-payload","errorCode":null,"errorMessage":"failed to read {} bytes of commit payload: {}","messagePattern":"failed to read (.+?) bytes of commit payload: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/commitlog/src/commit.rs","lineNumber":314,"sourceCode":"    /// [`ChecksumMismatch`] is returned.\n    pub fn decode<R: Read>(reader: R) -> io::Result<Option<Self>> {\n        Self::decode_internal(reader, DEFAULT_LOG_FORMAT_VERSION)\n    }\n\n    pub(crate) fn decode_internal<R: Read>(reader: R, log_format_version: u8) -> io::Result<Option<Self>> {\n        let mut reader = Crc32cReader::new(reader);\n\n        let v = if log_format_version == 0 {\n            Version::V0\n        } else {\n            Version::V1\n        };\n        let Some(hdr) = Header::decode_internal(&mut reader, v)? else {\n            return Ok(None);\n        };\n        let mut records = vec![0; hdr.len as usize];\n        reader.read_exact(&mut records).map_err(|e| {\n            io::Error::new(\n                e.kind(),\n                format!(\"failed to read {} bytes of commit payload: {}\", hdr.len, e),\n            )\n        })?;\n\n        let chk = reader.crc32c();\n        let crc = decode_u32(reader.into_inner())\n            .map_err(|e| io::Error::new(e.kind(), format!(\"failed to read checksum: {e}\")))?;\n\n        if chk != crc {\n            return Err(invalid_data(ChecksumMismatch));\n        }\n\n        Ok(Some(Self {\n            min_tx_offset: hdr.min_tx_offset,\n            epoch: hdr.epoch,\n            n: hdr.n,\n            records,","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/commitlog/src/commit.rs#L296-L332","documentation":"After a commit header decodes, the reader must read exactly `hdr.len` bytes of records. Failing to do so — almost always UnexpectedEof because the file ends early — is reported with the expected byte count and the underlying error. This signature means a commit was partially appended (the process or machine died mid-write), so the log is truncated after the previous commit.","triggerScenarios":"Header decoded but the file ends before `hdr.len` record bytes can be read: process killed mid-append, disk-full abort, or a data directory copied while being written.","commonSituations":"Power loss or SIGKILL during a reducer commit; disk filling up during append; snapshots or rsync of db files while the host runs.","solutions":["Let SpacetimeDB recovery proceed — a torn final commit is truncated away and the committed prefix is exposed","If the host refuses to open, restore the affected segment from backup or snapshot","Fix the root cause: free disk space, avoid killing the host mid-commit, snapshot with the host stopped"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match commit.decode(&mut reader) {\n    Ok(None) => break,\n    Ok(Some(c)) => commits.push(c),\n    Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {\n        // torn final commit: log is truncated; recover at the committed prefix\n        tracing::warn!(\"commitlog truncated mid-payload: {e}\");\n        break;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Shut the host down gracefully before snapshots or backups","Monitor disk space — a full disk mid-append tears the last commit","Expect one torn tail commit after any hard crash; recovery is designed to handle it"],"tags":["rust","io","commitlog","truncation","crash-recovery"],"backgroundTag":"truncated-log-read","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}