JuliusBrussee/caveman · error
read memory
Error message
read memory %s: %w
What it means
In memoryByID, any scan/query error other than sql.ErrNoRows is wrapped as "read memory <id>: %w". This distinguishes real read failures (corruption, lock, schema drift) from the benign not-found case, preserving the underlying cause for diagnosis.
Solutions
- Read the wrapped %w error to find the actual SQLite/scan failure.
- Reopen the store so migrations run if the schema is from an older version.
- Wait for or eliminate the competing writer holding the DB lock.
- If corruption is indicated, restore the database from backup.
Example fix
// before
m, err := store.History(id)
// after
if err != nil {
if !strings.Contains(err.Error(), "not found") {
log.Printf("read memory %s failed: %v", id, err) // inspect wrapped cause
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
m, err := store.History(id)
if err != nil {
if strings.Contains(err.Error(), "read memory") {
log.Printf("underlying cause: %v", errors.Unwrap(err))
}
return err
} Prevention
- Inspect errors.Unwrap(err) for the true SQLite failure.
- Let store-open migrations complete before reads.
- Resolve writer locks (check for stale WAL files or hung processes).
When it happens
Trigger: Store.History(id) with an existing ID but a failing underlying read: DB locked, corrupted, disk error, or a scanMemory type/conversion failure caused by schema drift (e.g. pre-migration rows with unexpected NULLs).
Common situations: Opening a database written by an older cavemem version before migrateMemorySchema completed, or reading while another process holds a long write transaction.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- count memories
- list memories
- store recovery for oversized memory
- check replacement memory
- close open arm
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/97a12050dc7e4aab.
Report an issue: GitHub.
Appendix: source
Thrown at mem/store.go:649
&supersededBy,
); err != nil {
return err
}
if validUntil.Valid {
memory.ValidUntil = &validUntil.String
}
memory.Supersedes = supersedes.String
memory.SupersededBy = supersededBy.String
return nil
}
func (s *Store) memoryByID(id string) (Memory, error) {
var memory Memory
if err := scanMemory(s.db.QueryRow(memorySelect+` WHERE id = ?`, id), &memory); err != nil {
if err == sql.ErrNoRows {
return Memory{}, fmt.Errorf("memory %s not found", id)
}
return Memory{}, fmt.Errorf("read memory %s: %w", id, err)
}
return memory, nil
}
// migrateMemorySchema upgrades pre-supersession stores in place. SQLite cannot
// add several columns in one statement, so each missing column is added
// independently and legacy created_at becomes valid_from.
func migrateMemorySchema(db *sql.DB) error {
rows, err := db.Query(`PRAGMA table_info(memories)`)
if err != nil {
return err
}
columns := map[string]bool{}
for rows.Next() {
var cid int
var name, kind string
var notNull, primaryKey int
var defaultValue anyView on GitHub (pinned to 3ee70a1026)