headroomlabs-ai/headroom · error · ValueError

Memory with ID {old_memory_id} not found

Error message

Memory with ID {old_memory_id} not found

What it means

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.

Source

Thrown at headroom/memory/adapters/sqlite.py:658

        Args:
            old_memory_id: ID of the memory to supersede.
            new_memory: The new memory that replaces it.
            supersede_time: When the supersession occurred (defaults to now).

        Returns:
            The saved new memory with lineage fields populated.

        Raises:
            ValueError: If the old memory is not found.
        """
        if supersede_time is None:
            supersede_time = datetime.now(timezone.utc).replace(tzinfo=None)

        # Get the old memory
        old_memory = await self.get(old_memory_id)
        if old_memory is None:
            raise ValueError(f"Memory with ID {old_memory_id} not found")

        # Update old memory's valid_until and superseded_by
        old_memory.valid_until = supersede_time
        old_memory.superseded_by = new_memory.id

        # Set up new memory's lineage
        new_memory.supersedes = old_memory_id
        new_memory.valid_from = supersede_time

        # Save both in a transaction
        with self._get_conn() as conn:
            # Update old memory
            conn.execute(
                """
                UPDATE memories
                SET valid_until = ?, superseded_by = ?
                WHERE id = ?
                """,

View on GitHub (pinned to 322425c43b)

Solutions

  1. Fetch the old memory first and verify it exists before building the superseding memory.
  2. Check for concurrent deletion (TTL jobs, compaction) and re-read IDs at operation time.
  3. Handle the ValueError as a signal the chain is already gone and skip/log the supersession.

Example fix

// before
await store.supersede(old_id, new_memory)

// after
if await store.get(old_id) is None:
    logger.warning("cannot supersede missing %s", old_id)
else:
    await store.supersede(old_id, new_memory)
Defensive patterns

Strategy: validation

Validate before calling

if await store.get(old_memory_id) is None:
    raise KeyError(f"memory {old_memory_id} vanished; cannot supersede")

Try / catch

try:
    saved = await store.supersede(old_id, new_memory)
except ValueError as e:
    logger.warning("supersede skipped: %s", e)

Prevention

When it happens

Trigger: 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.

Common situations: Stale IDs held from earlier sessions; race with a cleanup/TTL job that deleted the old memory; IDs from a different environment/database.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/62978e5b4483fb43. Report an issue: GitHub.