{"record":{"id":"2d3dd5fd6a8e9d30","repo":"vectordotdev/vector","slug":"checkpointer","errorCode":null,"errorMessage":"{}","messagePattern":"\\{\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/file-source-common/src/checkpointer.rs","lineNumber":289,"sourceCode":"            Err(error) if error.kind() == io::ErrorKind::NotFound => {\n                // This is expected, so no warning needed\n            }\n            Err(error) => {\n                warn!(message = \"Unable to load checkpoint data.\", %error);\n            }\n        }\n    }\n\n    async fn read_checkpoints_file(&self, path: &Path) -> Result<State, io::Error> {\n        // Possible optimization: mmap the file into a slice and pass it into serde_json instead of\n        // calling read_to_end. Need to investigate if this would work with tokio::fs::File\n\n        let mut reader = BufReader::new(File::open(path).await?);\n        let mut output = Vec::new();\n        reader.read_to_end(&mut output).await?;\n\n        serde_json::from_slice(&output[..])\n            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use chrono::{Duration, Utc};\n    use similar_asserts::assert_eq;\n    use tempfile::tempdir;\n    use tokio::fs;\n\n    use super::{\n        CHECKPOINT_FILE_NAME, Checkpoint, Checkpointer, FileFingerprint, FilePosition,\n        TMP_FILE_NAME,\n    };\n\n    #[test]\n    fn test_checkpointer_basics() {\n        let fingerprints = vec![","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/vectordotdev/vector/blob/0d4ab78a4f0d9c9e5d03a50108a2ae4d2f4b2460/lib/file-source-common/src/checkpointer.rs#L271-L307","documentation":"The disk buffer checkpointer loads its checkpoints from a JSON file. This error is raised when serde_json fails to deserialize the file's contents into the checkpoint map; the serde error is wrapped into an io::Error with ErrorKind::InvalidData. The message text is the underlying serde_json error (the \"{}\" template).","triggerScenarios":"The checkpoints file on disk is corrupt, truncated, or was written by an incompatible format/version; manual edits or a crash mid-write left invalid JSON; the file is empty or contains wrong types (e.g. a non-u64 where a sequence number is expected).","commonSituations":"Host crash or disk-full during checkpoint write; running a newer/older Vector against an old data directory; someone editing or replacing the buffer directory contents by hand.","solutions":["Restore the checkpoints file from backup or remove/rename it to let the buffer re-initialize (accepting re-delivery of buffered data).","Inspect the file's JSON with a validator to find the exact parse error location.","Recreate the affected disk buffer directory if the data can be discarded."],"exampleFix":"// before (corrupt checkpoints.json)\n{\"last_position\": \"abc\"}\n// after\n{\"last_position\": 1024}","handlingStrategy":"fallback","validationCode":"// validate checkpoint file before the buffer reads it\nfn checkpoint_file_valid(path: &Path) -> bool {\n    std::fs::read(path)\n        .map(|b| serde_json::from_slice::<serde_json::Value>(&b).is_ok())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match checkpointer.read_checkpoints().await {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        // corrupt checkpoints: rename aside and reinitialize\n        fs::rename(path, path.with_extension(\"corrupt\")).ok();\n        Default::default()\n    }\n    other => other?,\n}","preventionTips":["Write checkpoints atomically (temp file + rename) with fsync.","Never hand-edit files in the buffer data directory.","Monitor disk space to avoid truncated writes."],"tags":["buffers","checkpoint","json","io"],"backgroundTag":"json-decode-failed","analyzedSha":"0d4ab78a4f0d9c9e5d03a50108a2ae4d2f4b2460","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}