{"record":{"id":"75e78f133569b053","repo":"NousResearch/hermes-agent","slug":"memory-index-global-index-out-of-range","errorCode":null,"errorMessage":"memory index {global_index} out of range","messagePattern":"memory index (.+?) out of range","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"agent/learning_mutations.py","lineNumber":57,"sourceCode":"    if len(parts) != 3 or parts[0] != \"memory\" or parts[1] not in _MEMORY_FILES:\n        raise ValueError(f\"bad memory node id: {node_id!r}\")\n    try:\n        return parts[1], int(parts[2])\n    except ValueError as exc:\n        raise ValueError(f\"bad memory node id: {node_id!r}\") from exc\n\n\ndef _memory_local_index(source: str, global_index: int) -> int:\n    \"\"\"Global card index → position within the source's own file.\n\n    ``_memory_cards`` emits all ``MEMORY.md`` cards before ``USER.md`` cards, so\n    a profile card's local index is its global index minus the memory count.\n    \"\"\"\n    from agent.learning_graph import _memory_cards\n\n    cards = _memory_cards()\n    if not 0 <= global_index < len(cards):\n        raise IndexError(f\"memory index {global_index} out of range\")\n    if cards[global_index].get(\"source\") != source:\n        raise ValueError(\"memory node id is stale — refresh the graph\")\n    if source == \"memory\":\n        return global_index\n    return global_index - sum(1 for c in cards if c.get(\"source\") == \"memory\")\n\n\ndef _locate_memory(source: str, gidx: int) -> tuple[Path, list[str], int]:\n    \"\"\"Resolve a memory card to its file, all §-delimited entries, and local index.\n\n    Entries come from ``MemoryStore._read_file`` — the same parser the memory\n    tool uses — so journey indices stay aligned with what the graph renders.\n    \"\"\"\n    from tools.memory_tool import MemoryStore\n\n    path = _memories_dir() / _MEMORY_FILES[source]\n    if not path.exists():\n        raise ValueError(f\"{path.name} not found\")","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/learning_mutations.py#L39-L75","documentation":"IndexError from _memory_local_index: the global index embedded in the node id is outside the current card list produced by learning_graph._memory_cards(). The graph is a snapshot; if memory files changed (cards added/removed) or the id was fabricated, the index no longer resolves.","triggerScenarios":"Calling a mutation with 'memory:memory:<N>' where N >= len(_memory_cards()) or N < 0; typical after cards were deleted (shrinking the list) or when an id from a different profile/session is reused.","commonSituations":"Stale graph rendered before recent memory edits; concurrent mutation from another session that removed cards; profile mismatch (different HERMES_HOME has fewer memories).","solutions":["Re-render the learning graph and use a fresh node id from that output.","Verify the correct profile is active (HERMES_HOME) — card counts differ per profile.","If another process edits memory files, serialize mutations or re-check the graph immediately before mutating."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"from agent.learning_graph import _memory_cards\n\ndef index_in_range(global_index: int) -> bool:\n    return 0 <= global_index < len(_memory_cards())","typeGuard":null,"tryCatchPattern":"try:\n    mutate(node_id)\nexcept IndexError as e:\n    if \"out of range\" in str(e):\n        node_id = refresh_graph_and_rederive_id()\n        mutate(node_id)\n    else:\n        raise","preventionTips":["Check the index against the current card count immediately before mutating.","Re-render the graph after any memory add/delete and before the next mutation.","Treat node ids as ephemeral within a single render/mutate cycle."],"tags":["memory","learning-graph","stale-state"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}