{"record":{"id":"ff7b2748813654ce","repo":"JuliusBrussee/caveman","slug":"supersede-begin-w","errorCode":null,"errorMessage":"supersede begin: %w","messagePattern":"supersede begin: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mem/store.go","lineNumber":213,"sourceCode":"\treturn stored, nil\n}\n\n// Supersede atomically replaces one current memory with a new current version.\n// The old row remains durable for history and byte-exact audit, but normal recall\n// excludes it. An already-expired or unknown id fails closed.\nfunc (s *Store) Supersede(oldID, newText string) (Memory, error) {\n\tif strings.TrimSpace(oldID) == \"\" {\n\t\treturn Memory{}, fmt.Errorf(\"supersede requires old memory id\")\n\t}\n\tif strings.TrimSpace(newText) == \"\" {\n\t\treturn Memory{}, fmt.Errorf(\"cannot supersede with empty text\")\n\t}\n\tif err := validateMemorySize(newText); err != nil {\n\t\treturn Memory{}, err\n\t}\n\ttx, err := s.db.Begin()\n\tif err != nil {\n\t\treturn Memory{}, fmt.Errorf(\"supersede begin: %w\", err)\n\t}\n\tdefer tx.Rollback()\n\n\tvar old Memory\n\tif err := scanMemory(tx.QueryRow(memorySelect+` WHERE id = ? AND valid_until IS NULL`, oldID), &old); err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\treturn Memory{}, fmt.Errorf(\"memory %s is not current\", oldID)\n\t\t}\n\t\treturn Memory{}, fmt.Errorf(\"read current memory: %w\", err)\n\t}\n\tif old.Text == newText {\n\t\treturn Memory{}, fmt.Errorf(\"replacement text is identical to current memory\")\n\t}\n\tnewID := memID(newText)\n\tvar exists int\n\tif err := tx.QueryRow(`SELECT COUNT(*) FROM memories WHERE id = ?`, newID).Scan(&exists); err != nil {\n\t\treturn Memory{}, fmt.Errorf(\"check replacement memory: %w\", err)\n\t}","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/mem/store.go#L195-L231","documentation":"Supersede wraps failures from s.db.Begin() with this error. The atomic old→new replacement needs a transaction; if one cannot be started (db locked, closed, corrupted), Supersede aborts before any reads or writes, leaving lineage untouched.","triggerScenarios":"Calling Supersede when the SQLite db is heavily contended (long-held write lock by another connection), the store was already closed via Store.Close(), or the db file is unreadable/corrupt.","commonSituations":"Another process in a long transaction on the same memory db; calling Supersede after defer Store.Close() ran; read-only filesystem mounts preventing the write-journal setup.","solutions":["Check for other connections/processes holding write transactions on the same db; serialize access or retry with backoff.","Ensure the Store is not used after Close(); keep the Store alive for the call's lifetime.","Verify the db file and its directory are writable (journal/WAL files).","Inspect the wrapped cause to distinguish lock vs closed vs corrupt db."],"exampleFix":"// before\n_, err := store.Supersede(oldID, newText)\nif err != nil { panic(err) }\n// after\n_, err := store.Supersede(oldID, newText)\nif err != nil && strings.Contains(err.Error(), \"database is locked\") {\n    time.Sleep(250 * time.Millisecond)\n    _, err = store.Supersede(oldID, newText) // bounded retry\n}","handlingStrategy":"retry","validationCode":"// Go: ensure the store is still open before use\nif store == nil { return fmt.Errorf(\"store closed\") }","typeGuard":null,"tryCatchPattern":"_, err := store.Supersede(oldID, newText)\nif err != nil && strings.Contains(err.Error(), \"supersede begin\") {\n    time.Sleep(backoff)\n    _, err = store.Supersede(oldID, newText) // bounded retry on lock\n}","preventionTips":["Avoid holding long transactions on the memory db from other connections","Never use the Store after Close()","Keep db and journal files on a writable mount","Serialize supersede operations across processes"],"tags":["database","sqlite","transaction"],"backgroundTag":"database-write-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}