JuliusBrussee/caveman · error

check replacement memory

Error message

check replacement memory: %w

What it means

Supersede failed while checking whether a memory with the replacement's ID already exists (SELECT COUNT(*) FROM memories WHERE id = ?). Any scan/query error other than a clean result is wrapped here and the transaction is abandoned so no partial lineage is written.

Solutions

  1. Inspect the wrapped cause with errors.Unwrap to identify lock vs I/O vs schema failure.
  2. Set a busy_timeout pragma/DSN option and retry on SQLITE_BUSY.
  3. Check disk space and file permissions on the store path.
  4. Recreate or migrate the store file if the schema is outdated.

Example fix

// before
mem, err := store.Supersede(oldID, text)
if err != nil { return err }
// after
mem, err := store.Supersede(oldID, text)
if err != nil {
	var serr *sqlite.Error
	if errors.As(err, &serr) && serr.Code() == sqlite.RESULT_BUSY {
		time.Sleep(100 * time.Millisecond)
		mem, err = store.Supersede(oldID, text)
	}
	if err != nil { return err }
}
Defensive patterns

Strategy: retry

Validate before calling

if _, err := os.Stat(storePath); err != nil { return err }

Try / catch

for i := 0; i < 3; i++ {
	if _, err := store.Supersede(oldID, text); err == nil || !strings.Contains(err.Error(), "locked") {
		return err
	}
	time.Sleep(100 * time.Millisecond << i)
}

Prevention

When it happens

Trigger: Calling Store.Supersede(oldID, newText) when the COUNT query on the memories table fails: locked/corrupted database, disk I/O error, or schema mismatch.

Common situations: SQLite busy from concurrent writers; read-only or damaged database file; store opened with a different schema version than the one that created it.

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


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/9c179b16e3c277a3. Report an issue: GitHub.

Appendix: source

Thrown at mem/store.go:230

	if err != nil {
		return Memory{}, fmt.Errorf("supersede begin: %w", err)
	}
	defer tx.Rollback()

	var old Memory
	if err := scanMemory(tx.QueryRow(memorySelect+` WHERE id = ? AND valid_until IS NULL`, oldID), &old); err != nil {
		if err == sql.ErrNoRows {
			return Memory{}, fmt.Errorf("memory %s is not current", oldID)
		}
		return Memory{}, fmt.Errorf("read current memory: %w", err)
	}
	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,

View on GitHub (pinned to 3ee70a1026)