{"record":{"id":"a2e4f1a4cf8a643e","repo":"headroomlabs-ai/headroom","slug":"ambiguous-id-memory-id-matches-memory-id","errorCode":null,"errorMessage":"Ambiguous ID '{memory_id}'. Matches: {[memory.id[:8] for memory in matches]}","messagePattern":"Ambiguous ID '(.+?)'\\. Matches: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/cli/memory.py","lineNumber":224,"sourceCode":"    except Exception as exc:\n        print_warning(f\"Vector index cleanup incomplete: {exc}\")\n        ok = False\n\n    return ok\n\n\ndef _resolve_memory(store: SQLiteMemoryStore, memory_id: str) -> Memory:\n    \"\"\"Resolve an exact or unambiguous partial memory ID.\"\"\"\n    memory = asyncio.run(store.get(memory_id))\n    if memory is not None:\n        return memory\n\n    memories = asyncio.run(store.query(MemoryFilter(limit=10000, include_superseded=True)))\n    matches = [candidate for candidate in memories if candidate.id.startswith(memory_id)]\n    if not matches:\n        raise ValueError(f\"Memory not found: {memory_id}\")\n    if len(matches) > 1:\n        raise ValueError(\n            f\"Ambiguous ID '{memory_id}'. Matches: {[memory.id[:8] for memory in matches]}\"\n        )\n    return matches[0]\n\n\nasync def _apply_supersession_repair(\n    db_path: str,\n    old_memory_id: str,\n    new_memory_id: str,\n    vector_dimension: int,\n) -> tuple[Memory, Memory]:\n    \"\"\"Apply a repair through LocalBackend so indexes and cache are refreshed.\"\"\"\n    from ..memory.backends.local import LocalBackend, LocalBackendConfig\n\n    backend = LocalBackend(\n        LocalBackendConfig(\n            db_path=db_path,\n            vector_dimension=vector_dimension,","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/cli/memory.py#L206-L242","documentation":"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.","triggerScenarios":"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).","commonSituations":"Users abbreviating long UUIDs too aggressively; DBs with many memories where random short prefixes collide; scripts truncating IDs to a fixed short width.","solutions":["Extend the prefix until it matches exactly one ID listed in the error's Matches array","Copy the full ID from `headroom memory list` output","In scripts, never truncate IDs below the length that keeps them unique — store full IDs","Prune/supersede old memories if ID collisions come from duplicate near-identical entries"],"exampleFix":"# before\n$ headroom memory show 3f\n# Ambiguous ID '3f'. Matches: ['3f9c1d2e', '3f77aa01']\n\n# after\n$ headroom memory show 3f9c1d2e4a5b6c7d","handlingStrategy":"validation","validationCode":"import asyncio\nfrom headroom.memory import MemoryFilter\n\ndef unique_prefix_ok(store, prefix: str) -> tuple[bool, int]:\n    if asyncio.run(store.get(prefix)) is not None:\n        return True, 1\n    hits = [m for m in asyncio.run(store.query(MemoryFilter(limit=10000, include_superseded=True)))\n            if m.id.startswith(prefix)]\n    return len(hits) == 1, len(hits)","typeGuard":null,"tryCatchPattern":"try:\n    mem = _resolve_memory(store, memory_id)\nexcept ValueError as e:\n    if str(e).startswith(\"Ambiguous ID\"):\n        # message lists candidate 8-char prefixes — extend and retry\n        candidates = parse_matches(str(e))\n        raise SystemExit(f\"extend prefix; candidates: {candidates}\")\n    raise","preventionTips":["Store full memory IDs in automation; never truncate below ~12 chars","Parse the Matches list from the error to auto-extend the prefix","Reduce superseded duplicates so prefix collisions are rare"],"tags":["cli","memory","id-resolution","ambiguity","valueerror"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}