headroomlabs-ai/headroom · error · ValueError

Ambiguous ID '{memory_id}'. Matches: {[memory.id[:8] for mem

Error message

Ambiguous ID '{memory_id}'. Matches: {[memory.id[:8] for memory in matches]}

What it means

When _resolve_memory's exact lookup misses but multiple stored memory IDs share the given prefix, it refuses to guess and raises ValueError listing the first 8 chars of every match. This is a deliberate unambiguity guarantee: prefix shortcuts must resolve to exactly one memory or the command aborts before mutating anything.

Source

Thrown at headroom/cli/memory.py:224

    except Exception as exc:
        print_warning(f"Vector index cleanup incomplete: {exc}")
        ok = False

    return ok


def _resolve_memory(store: SQLiteMemoryStore, memory_id: str) -> Memory:
    """Resolve an exact or unambiguous partial memory ID."""
    memory = asyncio.run(store.get(memory_id))
    if memory is not None:
        return memory

    memories = asyncio.run(store.query(MemoryFilter(limit=10000, include_superseded=True)))
    matches = [candidate for candidate in memories if candidate.id.startswith(memory_id)]
    if not matches:
        raise ValueError(f"Memory not found: {memory_id}")
    if len(matches) > 1:
        raise ValueError(
            f"Ambiguous ID '{memory_id}'. Matches: {[memory.id[:8] for memory in matches]}"
        )
    return matches[0]


async def _apply_supersession_repair(
    db_path: str,
    old_memory_id: str,
    new_memory_id: str,
    vector_dimension: int,
) -> tuple[Memory, Memory]:
    """Apply a repair through LocalBackend so indexes and cache are refreshed."""
    from ..memory.backends.local import LocalBackend, LocalBackendConfig

    backend = LocalBackend(
        LocalBackendConfig(
            db_path=db_path,
            vector_dimension=vector_dimension,

View on GitHub (pinned to 322425c43b)

Solutions

  1. Extend the prefix until it matches exactly one ID listed in the error's Matches array
  2. Copy the full ID from `headroom memory list` output
  3. In scripts, never truncate IDs below the length that keeps them unique — store full IDs
  4. Prune/supersede old memories if ID collisions come from duplicate near-identical entries

Example fix

# before
$ headroom memory show 3f
# Ambiguous ID '3f'. Matches: ['3f9c1d2e', '3f77aa01']

# after
$ headroom memory show 3f9c1d2e4a5b6c7d
Defensive patterns

Strategy: validation

Validate before calling

import asyncio
from headroom.memory import MemoryFilter

def unique_prefix_ok(store, prefix: str) -> tuple[bool, int]:
    if asyncio.run(store.get(prefix)) is not None:
        return True, 1
    hits = [m for m in asyncio.run(store.query(MemoryFilter(limit=10000, include_superseded=True)))
            if m.id.startswith(prefix)]
    return len(hits) == 1, len(hits)

Try / catch

try:
    mem = _resolve_memory(store, memory_id)
except ValueError as e:
    if str(e).startswith("Ambiguous ID"):
        # message lists candidate 8-char prefixes — extend and retry
        candidates = parse_matches(str(e))
        raise SystemExit(f"extend prefix; candidates: {candidates}")
    raise

Prevention

When it happens

Trigger: Passing a short prefix (e.g. 2-4 hex chars) that is a prefix of several memory IDs, e.g. `headroom memory show 3f` when 3f9c1d2e... and 3f77aa01... both exist (superseded memories included).

Common situations: Users abbreviating long UUIDs too aggressively; DBs with many memories where random short prefixes collide; scripts truncating IDs to a fixed short width.

Related errors


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