JuliusBrussee/caveman · error

: : inspect database

Error message

%w: %w: inspect database%s: %v

What it means

Inspecting one of the database files (main, -wal, or -shm) failed with an error other than ErrNotExist. The library cannot confirm file identity, so it returns ErrStorageChanged wrapped with errStorageUnverifiable. Per checkGeneration, unverifiable failures fail only the current operation — the store is not terminally quarantined — but the call does not proceed.

Solutions

  1. Fix permissions/ownership on the specific file named in the error message.
  2. Resolve competing access: close other processes holding the DB/WAL open, or move to a per-user store path to avoid cross-process contention.
  3. Check disk/filesystem health if the error is an I/O error; fsck or remount the volume.
  4. Retry once conditions clear — this error is not latched, later calls may succeed.
  5. Exclude the store directory from antivirus/indexer interference if locks recur.

Example fix

// before
-rw-r----- ccr.db -rw------- ccr.db-wal (mixed owners)
// after
chown "$USER" ~/.caveman/ccr.db* && chmod 600 ~/.caveman/ccr.db*
Defensive patterns

Strategy: retry

Validate before calling

for _, sfx := range []{"", "-wal", "-shm"} {
    if _, err := os.Stat(dbPath + sfx); err != nil && !os.IsNotExist(err) {
        return fmt.Errorf("%s not inspectable: %v", dbPath+sfx, err)
    }
}

Try / catch

if err != nil && errors.Is(err, ccr.ErrStorageChanged) && !storePermanentlyDead(err) {
    time.Sleep(500 * time.Millisecond)
    err = store.Put(rec) // unverifiable failures are not latched; retry
}

Prevention

When it happens

Trigger: inspectSQLiteFile returns a non-ErrNotExist error for path, path+"-wal", or path+"-shm": permission errors on an individual file, EIO on a network volume, a file lock held by another process, or a stat failure caused by a path component change.

Common situations: WAL sidecar made unreadable by an ACL change; another SQLite process holds an exclusive lock on the -wal file; corrupted directory entry on a failing disk; network home briefly offline mid-operation.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at engine/ccr/store_generation.go:67

	if errors.Is(err, os.ErrNotExist) {
		return files, fmt.Errorf("%w: database parent changed", ErrStorageChanged)
	}
	if err != nil {
		return files, fmt.Errorf("%w: %w: inspect database parent: %v", ErrStorageChanged, errStorageUnverifiable, err)
	}
	if err := validateSQLiteParentSecurity(parent, info); err != nil {
		return files, fmt.Errorf("%w: %w: %v", ErrStorageChanged, errStorageUnverifiable, err)
	}
	for i, suffix := range sqliteSuffixes {
		info, err := inspectSQLiteFile(path + suffix)
		if errors.Is(err, os.ErrNotExist) && i != 0 {
			continue
		}
		if errors.Is(err, os.ErrNotExist) {
			return files, fmt.Errorf("%w: inspect database%s: %v", ErrStorageChanged, suffix, err)
		}
		if err != nil {
			return files, fmt.Errorf("%w: %w: inspect database%s: %v", ErrStorageChanged, errStorageUnverifiable, suffix, err)
		}
		if !info.Mode().IsRegular() {
			return files, fmt.Errorf("%w: refusing non-regular database%s", ErrStorageChanged, suffix)
		}
		files[i] = info
	}
	return files, nil
}

func sameSQLiteFile(a, b os.FileInfo) bool {
	if a == nil || b == nil {
		return a == nil && b == nil
	}
	return os.SameFile(a, b)
}

// sameExisting also permits sidecars to be created while opening a clean DB.
func (a sqliteGeneration) sameExisting(b sqliteGeneration) bool {

View on GitHub (pinned to 3ee70a1026)