JuliusBrussee/caveman · error
insert replacement memory
Error message
insert replacement memory: %w
What it means
Supersede failed while inserting the replacement memory row into the memories table. The insert runs inside the supersede transaction, so any failure (constraint violation, lock, I/O error) aborts the whole operation and no lineage change is persisted.
Solutions
- Check the wrapped cause (errors.Unwrap / errors.As on the driver error).
- Free disk space / verify write permissions on the store file.
- Add busy_timeout and retry on lock errors.
- Confirm the store file matches the current schema version.
Example fix
// before
new, err := store.Supersede(oldID, text)
if err != nil { return err }
// after
new, err := store.Supersede(oldID, text)
if err != nil {
return fmt.Errorf("supersede %s: %w", oldID, err) // surface wrapped cause for diagnosis
} Defensive patterns
Strategy: try-catch
Validate before calling
if err := checkDiskSpace(storeDir); err != nil { return err } Try / catch
_, err := store.Supersede(oldID, text)
if err != nil {
log.Printf("insert replacement failed: %v", errors.Unwrap(err))
return err
} Prevention
- Monitor free disk space for the store directory
- Avoid read-only mounts for the database file
- Set busy_timeout and serialize writers
- Keep the store schema aligned with the library version
When it happens
Trigger: Calling Store.Supersede(oldID, newText) when the INSERT of the new (id, text, created_at, valid_from, supersedes) row fails: disk full, database locked, constraint violation, or corrupted schema.
Common situations: Disk quota exceeded while writing the SQLite file; concurrent writers causing SQLITE_BUSY; database file opened read-only; schema drift between library versions.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/afcab6370a605eff.
Report an issue: GitHub.
Appendix: source
Thrown at mem/store.go:242
if old.Text == newText {
return Memory{}, fmt.Errorf("replacement text is identical to current memory")
}
newID := memID(newText)
var exists int
if err := tx.QueryRow(`SELECT COUNT(*) FROM memories WHERE id = ?`, newID).Scan(&exists); err != nil {
return Memory{}, fmt.Errorf("check replacement memory: %w", err)
}
if exists > 0 {
return Memory{}, fmt.Errorf("replacement memory %s already exists", newID)
}
now := time.Now().UTC().Format(time.RFC3339Nano)
if _, err := tx.Exec(
`INSERT INTO memories
(id, text, created_at, valid_from, supersedes)
VALUES (?, ?, ?, ?, ?)`,
newID, newText, now, now, oldID,
); err != nil {
return Memory{}, fmt.Errorf("insert replacement memory: %w", err)
}
res, err := tx.Exec(
`UPDATE memories
SET valid_until = ?, superseded_by = ?
WHERE id = ? AND valid_until IS NULL`,
now, newID, oldID,
)
if err != nil {
return Memory{}, fmt.Errorf("expire old memory: %w", err)
}
if n, _ := res.RowsAffected(); n != 1 {
return Memory{}, fmt.Errorf("memory %s changed during supersede", oldID)
}
if err := tx.Commit(); err != nil {
return Memory{}, fmt.Errorf("supersede commit: %w", err)
}
return Memory{
ID: newID,View on GitHub (pinned to 3ee70a1026)