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
- Fix permissions/ownership on the specific file named in the error message.
- Resolve competing access: close other processes holding the DB/WAL open, or move to a per-user store path to avoid cross-process contention.
- Check disk/filesystem health if the error is an I/O error; fsck or remount the volume.
- Retry once conditions clear — this error is not latched, later calls may succeed.
- 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
- Keep per-file permissions consistent (0600, same owner) on ccr.db*
- Avoid NFS/removable volumes for the store
- Close other SQLite processes before operating on the same files
- Exclude the directory from indexers and AV that lock files
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
- inspect sqlite parent ACL
- inspect sqlite parent
- secure sqlite sidecar
- sqlite parent has no restrictive DACL
- sqlite parent has no security descriptor
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)