{"record":{"id":"12cfc287059572c4","repo":"RyanCodrai/turbovec","slug":"persisted-store-is-corrupt-len-missing-what","errorCode":null,"errorMessage":"persisted store is corrupt: {len(missing)} {what} id(s) present in `{mapping_name}` but missing from `{sidecar_name}` (e.g. {sample}). The JSON side-car's maps are out of sync.","messagePattern":"persisted store is corrupt: (.+?) (.+?) id\\(s\\) present in `(.+?)` but missing from `(.+?)` \\(e\\.g\\. (.+?)\\)\\. The JSON side-car's maps are out of sync\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"critical","filePath":"turbovec-python/python/turbovec/_persist.py","lineNumber":510,"sourceCode":"        what: noun for error messages (e.g. \"document\", \"node\").\n        mapping_name: side-car field name of the id -> handle map.\n        sidecar_name: side-car field name of the id -> payload map.\n\n    Raises:\n        ValueError: if either map holds an id the other lacks.\n    \"\"\"\n    mapping_set = set(mapping_keys)\n    sidecar_set = set(sidecar_keys)\n    if mapping_set == sidecar_set:\n        return\n    missing = mapping_set - sidecar_set\n    if missing:\n        # key=repr: a hand-corrupted side-car can hold mixed-type ids\n        # (JSON arrays survive parsing with e.g. an int among strings),\n        # which plain sorted() would turn into a TypeError instead of\n        # the promised ValueError.\n        sample = \", \".join(repr(k) for k in sorted(missing, key=repr)[:3])\n        raise ValueError(\n            f\"persisted store is corrupt: {len(missing)} {what} id(s) present \"\n            f\"in `{mapping_name}` but missing from `{sidecar_name}` \"\n            f\"(e.g. {sample}). The JSON side-car's maps are out of sync.\"\n        )\n    extraneous = sidecar_set - mapping_set\n    sample = \", \".join(repr(k) for k in sorted(extraneous, key=repr)[:3])\n    raise ValueError(\n        f\"persisted store is corrupt: {len(extraneous)} {what} id(s) present \"\n        f\"in `{sidecar_name}` but missing from `{mapping_name}` \"\n        f\"(e.g. {sample}). The JSON side-car's maps are out of sync.\"\n    )\n\n\n__all__ = [\"check_persisted_handles\", \"check_schema_version\", \"check_sidecar_keysets\"]\n","sourceCodeStart":492,"sourceCodeEnd":525,"githubUrl":"https://github.com/RyanCodrai/turbovec/blob/ccab9f325e6ce2a270a87daf01ae4e443bcf2d49/turbovec-python/python/turbovec/_persist.py#L492-L525","documentation":"check_sidecar_keysets cross-checks the id-keyed maps in the JSON side-car (e.g. doc-id to handle vs metadata maps). Every id present in the primary mapping must also appear in the dependent side-car map; missing ids mean the maps were edited or written independently, so loading is aborted with ValueError listing up to three sample ids. The sample is sorted by repr so mixed-type ids (int among strings from a corrupted JSON array) yield ValueError, not TypeError.","triggerScenarios":"load / from_persist_path (or direct check_sidecar_keysets calls) on a side-car whose maps have diverged: an id added to one map but not the other via manual editing, partial writes, or merging files from different saves; also hand-corrupted side-cars holding mixed-type ids (int among strings).","commonSituations":"Hand-editing the JSON side-car and missing one map; a script updating docs but not metadata maps; restoring only part of the side-car from backup; external corruption inserting a non-string id into a JSON array.","solutions":["Restore the full side-car (all maps together) from the same backup as the .tvim index.","Rebuild the store from source data if no consistent backup exists.","If repairing manually, add the missing ids to the dependent map — and verify every other keyset check (extraneous ids) also passes.","Pre-validate before load: `set(primary) - set(sidecar_map)` empty; wrap in try/except ValueError for a clean corruption message."],"exampleFix":"// before\n# docs map has id \"b\", meta map lacks it\nstore = turbovec.load('store.tvim')\n// after\nmissing = set(doc_map) - set(meta_map)\nif missing:\n    raise RuntimeError(f'side-car maps out of sync: {missing}; restore backup')\nstore = turbovec.load('store.tvim')","handlingStrategy":"validation","validationCode":"def keysets_match(primary, sidecar_map) -> bool:\n    return set(primary) == set(sidecar_map)\n# compare every id-keyed map pair in the side-car before load","typeGuard":null,"tryCatchPattern":"try:\n    store = turbovec.load(path)\nexcept ValueError as e:\n    if \"missing from\" in str(e):\n        restore_full_sidecar_from_backup()\n    else:\n        raise","preventionTips":["Update all side-car maps together through the library API, never one map alone.","Restore the entire side-car file, not individual maps.","Validate keyset equality (set(primary) == set(sidecar)) before loading externally-edited stores.","Treat mixed-type ids in the side-car as corruption: coerce ids to str on write and verify on read."],"tags":["python","persistence","corruption","consistency","json"],"backgroundTag":"checksum-mismatch","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"}