JuliusBrussee/caveman · error

memory %s not found

Error message

memory %s not found

What it means

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).

Source

Thrown at mem/store.go:647

		&validUntil,
		&supersedes,
		&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

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Verify the id exists before acting: query the row or call a lookup and handle absence explicitly
  2. Check which store file you are attached to — differing CAVEMAN_HOME/data paths between writer and reader is the usual cause
  3. If the memory was deleted, decide whether to recreate it (Remember) or skip the operation; do not loop-retry a not-found

Example fix

// before
hist, err := store.History(memID) // stale id from an old DB

// after
if _, err := store.History(memID); err != nil {
    if strings.HasSuffix(err.Error(), "not found") {
        // re-create or skip gracefully
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := store.History(id); err != nil { /* presence check, or cache the result */ }

Type guard

func isNotFound(err error) bool {
    return err != nil && strings.HasSuffix(err.Error(), "not found")
}

Try / catch

hist, err := store.History(id)
if err != nil {
    if isNotFound(err) {
        // skip, re-create via Remember, or ask the user — do not retry
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/60883e063428a838. Report an issue: GitHub.