{"record":{"id":"62978e5b4483fb43","repo":"headroomlabs-ai/headroom","slug":"memory-with-id-old-memory-id-not-found","errorCode":null,"errorMessage":"Memory with ID {old_memory_id} not found","messagePattern":"Memory with ID (.+?) not found","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/memory/adapters/sqlite.py","lineNumber":658,"sourceCode":"\n        Args:\n            old_memory_id: ID of the memory to supersede.\n            new_memory: The new memory that replaces it.\n            supersede_time: When the supersession occurred (defaults to now).\n\n        Returns:\n            The saved new memory with lineage fields populated.\n\n        Raises:\n            ValueError: If the old memory is not found.\n        \"\"\"\n        if supersede_time is None:\n            supersede_time = datetime.now(timezone.utc).replace(tzinfo=None)\n\n        # Get the old memory\n        old_memory = await self.get(old_memory_id)\n        if old_memory is None:\n            raise ValueError(f\"Memory with ID {old_memory_id} not found\")\n\n        # Update old memory's valid_until and superseded_by\n        old_memory.valid_until = supersede_time\n        old_memory.superseded_by = new_memory.id\n\n        # Set up new memory's lineage\n        new_memory.supersedes = old_memory_id\n        new_memory.valid_from = supersede_time\n\n        # Save both in a transaction\n        with self._get_conn() as conn:\n            # Update old memory\n            conn.execute(\n                \"\"\"\n                UPDATE memories\n                SET valid_until = ?, superseded_by = ?\n                WHERE id = ?\n                \"\"\",","sourceCodeStart":640,"sourceCodeEnd":676,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/adapters/sqlite.py#L640-L676","documentation":"Raised by the SQLite memory store's supersede operation when the old memory ID does not exist. Supersession must link an existing old memory to a new one, so a missing old record (checked via get) aborts before any lineage fields are written.","triggerScenarios":"Calling supersede(old_id, new_memory) after the old memory was deleted; passing an ID with a typo or wrong format; concurrent deletion between the caller's read and the supersede call.","commonSituations":"Stale IDs held from earlier sessions; race with a cleanup/TTL job that deleted the old memory; IDs from a different environment/database.","solutions":["Fetch the old memory first and verify it exists before building the superseding memory.","Check for concurrent deletion (TTL jobs, compaction) and re-read IDs at operation time.","Handle the ValueError as a signal the chain is already gone and skip/log the supersession."],"exampleFix":"// before\nawait store.supersede(old_id, new_memory)\n\n// after\nif await store.get(old_id) is None:\n    logger.warning(\"cannot supersede missing %s\", old_id)\nelse:\n    await store.supersede(old_id, new_memory)","handlingStrategy":"validation","validationCode":"if await store.get(old_memory_id) is None:\n    raise KeyError(f\"memory {old_memory_id} vanished; cannot supersede\")","typeGuard":null,"tryCatchPattern":"try:\n    saved = await store.supersede(old_id, new_memory)\nexcept ValueError as e:\n    logger.warning(\"supersede skipped: %s\", e)","preventionTips":["Re-read IDs at operation time instead of caching them across sessions.","Watch for TTL/cleanup jobs that can delete the old memory concurrently."],"tags":["sqlite","supersession","lineage","not-found"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}