{"record":{"id":"faa4098c013b33b8","repo":"RyanCodrai/turbovec","slug":"cannot-sync-a-lazy-index-that-has-never-seen-an-ad","errorCode":null,"errorMessage":"cannot sync a lazy index that has never seen an add or calibrate","messagePattern":"cannot sync a lazy index that has never seen an add or calibrate","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"turbovec/src/lib.rs","lineNumber":1822,"sourceCode":"\n    /// One full v7 image of this index, in memory.\n    pub(crate) fn v7_image(&self, kind: u8, ids_full: Option<&[u64]>) -> std::io::Result<Vec<u8>> {\n        self.with_sync_source(kind, ids_full, io_v7::image_bytes)\n    }\n\n    /// Bytes [`Self::v7_image`] would produce, without building it.\n    pub(crate) fn v7_image_len(&self, kind: u8, ids_full: Option<&[u64]>) -> std::io::Result<usize> {\n        self.with_sync_source(kind, ids_full, io_v7::image_len)\n    }\n\n    pub(crate) fn sync_v7_impl(\n        &mut self,\n        path: &Path,\n        kind: u8,\n        ids_full: Option<&[u64]>,\n    ) -> std::io::Result<()> {\n        let Some(dim) = self.dim else {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"cannot sync a lazy index that has never seen an add or calibrate\",\n            ));\n        };\n        if self.blocked.get().is_none() {\n            self.packed();\n        }\n        if self.boundaries.get().is_none() || self.centroids.get().is_none() {\n            let (b, c) = codebook::codebook(self.bit_width, dim);\n            let _ = self.boundaries.set(b);\n            let _ = self.centroids.set(c);\n        }\n        let geo = io_v7::Geo {\n            kind,\n            dim,\n            bit_width: self.bit_width,\n            n_calib: self.tqplus_shift.len(),\n        };","sourceCodeStart":1804,"sourceCodeEnd":1840,"githubUrl":"https://github.com/RyanCodrai/turbovec/blob/ccab9f325e6ce2a270a87daf01ae4e443bcf2d49/turbovec/src/lib.rs#L1804-L1840","documentation":"sync/save on a lazy index fails with InvalidInput when self.dim is None — the lazily-built index has never had a vector added nor been calibrated, so there is no dimension to persist. The library refuses to write a meaningless empty file instead of producing an unloadable artifact.","triggerScenarios":"Calling sync (or the save path that takes kind/ids_full) on a freshly constructed lazy Index before any add() or calibrate() call.","commonSituations":"Error-handling code that syncs unconditionally after a failed build; scaffolding that wires up persistence before data ingestion; tests instantiating an index and immediately persisting it.","solutions":["Add at least one vector or run calibrate() before syncing","Check that ingestion succeeded (no silent empty batch) before syncing","Skip the sync when the index is empty","Guard the sync behind a check that data was actually loaded"],"exampleFix":"// before\nlet mut idx = Index::lazy();\nidx.sync(path, KIND, None)?; // Err\n// after\nlet mut idx = Index::lazy();\nfor v in vectors { idx.add(v)?; }\nidx.sync(path, KIND, None)?;","handlingStrategy":"validation","validationCode":"if idx.dim().is_none() {\n    return Err(anyhow!(\"index is empty; add vectors or calibrate before sync\"));\n}\nidx.sync(path, KIND, None)?;","typeGuard":"fn syncable(idx: &Index) -> bool { idx.dim().is_some() }","tryCatchPattern":"match idx.sync(path, KIND, None) {\n    Err(e) if e.to_string().contains(\"never seen an add or calibrate\") => {\n        eprintln!(\"skipping sync: index is empty\");\n    }\n    other => other?,\n}","preventionTips":["Sync only after ingestion confirms rows added","Assert non-empty index in save paths","Order pipelines: build -> add/calibrate -> sync"],"tags":["state-error","lazy-index","preconditions"],"backgroundTag":"invalid-state-transition","analyzedSha":"ccab9f325e6ce2a270a87daf01ae4e443bcf2d49","analyzedAt":"2026-09-06T08:39:18.516Z","contentChangedAt":"2026-09-06T08:39:18.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}