JuliusBrussee/caveman · error
repair forgotten successor
Error message
repair forgotten successor: %w
What it means
When the forgotten memory has a successor (superseded_by is set), Forget() rewrites the successor's supersedes pointer (usually to NULL) so the chain skips the deleted record. A failure of this UPDATE rolls back the transaction and is wrapped as this error. As with the predecessor repair, this is a SQLite write failure, not a lineage-logic error.
Solutions
- Verify write access to the DB and its -wal/-shm files; fix ownership/permissions and retry.
- Free disk space if `df -h` shows the volume full, then retry the forget.
- Check `lsof <db>` for other writers; stop them or add a busy timeout (`?_busy_timeout=5000`) to ride out short locks.
- If corruption is suspected (`PRAGMA integrity_check` fails), restore from a clean backup; stop writers before copying DB files.
Example fix
# before: cleanup fails on a full disk $ cavemem forget old-version-id # forget: repair forgotten successor: database or disk is full # after: free space, then retry $ df -h /data && cavemem forget old-version-id
Defensive patterns
Strategy: retry
Validate before calling
// Go: verify free disk space before write-heavy store operations
const minFreeBytes = 10 << 20
func hasDiskSpace(path string) bool {
var st syscall.Statfs_t
if syscall.Statfs(filepath.Dir(path), &st) != nil { return false }
return int64(st.Bavail)*int64(st.Bsize) > minFreeBytes
} Type guard
null
Try / catch
ok, err := store.Forget(id)
if err != nil && strings.Contains(err.Error(), "repair forgotten successor") {
// fix storage condition (space/permissions/lock) then retry; transaction rolled back cleanly
return retryForget(store, id, 3)
} Prevention
- Monitor free space on the DB volume; full disks are the top cause of mid-transaction write failures.
- Keep only one writer process per database, or enable WAL mode with a busy timeout.
- Don't chmod the DB read-only while a long-lived server holds it open.
- Run `PRAGMA integrity_check;` after any crash; corrupted pages cause subsequent UPDATE failures.
When it happens
Trigger: Calling Forget(id) on a superseded (older) version while the database is read-only or full, the write lock is held by another process, or the affected pages are corrupted.
Common situations: Forgetting history entries from a DB opened on a read-only volume, a full disk during cleanup of old versions, two processes deleting simultaneously, or corrupted WAL sidecar files blocking writes.
Related errors
- forget
- repair forgotten predecessor
- broken supersession history at
- cyclic supersession history at
- forget begin
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/a9b62aa98ea10db7.
Report an issue: GitHub.
Appendix: source
Thrown at mem/store.go:353
if err == sql.ErrNoRows {
return false, nil
}
return false, fmt.Errorf("read forgotten memory: %w", err)
}
if supersedes.Valid {
if _, err := tx.Exec(
`UPDATE memories SET superseded_by = ? WHERE id = ?`,
nullableLineageID(supersededBy), supersedes.String,
); err != nil {
return false, fmt.Errorf("repair forgotten predecessor: %w", err)
}
}
if supersededBy.Valid {
if _, err := tx.Exec(
`UPDATE memories SET supersedes = ? WHERE id = ?`,
nullableLineageID(supersedes), supersededBy.String,
); err != nil {
return false, fmt.Errorf("repair forgotten successor: %w", err)
}
}
if _, err := tx.Exec(`DELETE FROM memories WHERE id = ?`, id); err != nil {
return false, fmt.Errorf("forget: %w", err)
}
if err := tx.Commit(); err != nil {
return false, fmt.Errorf("forget commit: %w", err)
}
return true, nil
}
func nullableLineageID(value sql.NullString) any {
if value.Valid {
return value.String
}
return nil
}
View on GitHub (pinned to 3ee70a1026)