{"record":{"id":"60883e063428a838","repo":"JuliusBrussee/caveman","slug":"memory-s-not-found","errorCode":null,"errorMessage":"memory %s not found","messagePattern":"memory (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mem/store.go","lineNumber":647,"sourceCode":"\t\t&validUntil,\n\t\t&supersedes,\n\t\t&supersededBy,\n\t); err != nil {\n\t\treturn err\n\t}\n\tif validUntil.Valid {\n\t\tmemory.ValidUntil = &validUntil.String\n\t}\n\tmemory.Supersedes = supersedes.String\n\tmemory.SupersededBy = supersededBy.String\n\treturn nil\n}\n\nfunc (s *Store) memoryByID(id string) (Memory, error) {\n\tvar memory Memory\n\tif err := scanMemory(s.db.QueryRow(memorySelect+` WHERE id = ?`, id), &memory); err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\treturn Memory{}, fmt.Errorf(\"memory %s not found\", id)\n\t\t}\n\t\treturn Memory{}, fmt.Errorf(\"read memory %s: %w\", id, err)\n\t}\n\treturn memory, nil\n}\n\n// migrateMemorySchema upgrades pre-supersession stores in place. SQLite cannot\n// add several columns in one statement, so each missing column is added\n// independently and legacy created_at becomes valid_from.\nfunc migrateMemorySchema(db *sql.DB) error {\n\trows, err := db.Query(`PRAGMA table_info(memories)`)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcolumns := map[string]bool{}\n\tfor rows.Next() {\n\t\tvar cid int\n\t\tvar name, kind string","sourceCodeStart":629,"sourceCodeEnd":665,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/mem/store.go#L629-L665","documentation":"The internal lookup memoryByID found no row with the given id (sql.ErrNoRows). Every public path built on it — History, Supersede's target fetch, Forget-style operations — surfaces this as 'memory <id> not found'. It means the id is well-formed but absent from the memories table (or already deleted).","triggerScenarios":"Calling History(id) / Supersede(oldID, ...) / anything resolving a single memory with an id that was never inserted, was Forget-deleted, or came from a different database file. Also when an id string is truncated or has trailing whitespace/encoding damage so the exact match fails.","commonSituations":"Persisting ids across restarts while the store was recreated or pointed at another path (CAVEMAN_HOME change); using an id from a test fixture against the production DB; retrying an operation whose earlier attempt already deleted the memory.","solutions":["Verify the id exists before acting: query the row or call a lookup and handle absence explicitly","Check which store file you are attached to — differing CAVEMAN_HOME/data paths between writer and reader is the usual cause","If the memory was deleted, decide whether to recreate it (Remember) or skip the operation; do not loop-retry a not-found"],"exampleFix":"// before\nhist, err := store.History(memID) // stale id from an old DB\n\n// after\nif _, err := store.History(memID); err != nil {\n    if strings.HasSuffix(err.Error(), \"not found\") {\n        // re-create or skip gracefully\n    }\n}","handlingStrategy":"try-catch","validationCode":"if _, err := store.History(id); err != nil { /* presence check, or cache the result */ }","typeGuard":"func isNotFound(err error) bool {\n    return err != nil && strings.HasSuffix(err.Error(), \"not found\")\n}","tryCatchPattern":"hist, err := store.History(id)\nif err != nil {\n    if isNotFound(err) {\n        // skip, re-create via Remember, or ask the user — do not retry\n    }\n    return err\n}","preventionTips":["Pin a single store path (CAVEMAN_HOME) across all writers and readers","Treat persisted ids as perishable: re-validate before use after restarts","Distinguish not-found from transient IO errors before choosing a recovery path"],"tags":["go","not-found","memory-store","lifecycle"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}