JuliusBrussee/caveman · error
%w: %w: %v
Error message
%w: %w: %v
What it means
After a successful os.Stat on the database parent, inspectSQLiteGeneration calls validateSQLiteParentSecurity to confirm the directory's permissions are safe. If that validation fails (mode loosened or otherwise insecure), the error is wrapped as ErrStorageChanged plus errStorageUnverifiable: identity could not be verified under the required security posture. As with other unverifiable failures, checkGeneration fails the current operation without latching terminal quarantine.
Solutions
- Set the database parent directory to a secure mode, typically 0700 for the owning user: chmod 700 <dir>.
- Ensure the directory is owned by the user running the engine (chown).
- Move the store out of shared world-writable locations like /tmp or /var/tmp into the user's home.
- If a tool keeps resetting the mode, exclude this directory from it or set the store path elsewhere via configuration.
- Retry the operation after fixing: this unverifiable error is not latched as terminal quarantine.
Example fix
// before os.MkdirAll(dataDir, 0o777) // after os.MkdirAll(dataDir, 0o700)
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(filepath.Dir(dbPath))
if err == nil && info.Mode().Perm()&0o077 != 0 {
return fmt.Errorf("store dir %s too open: %v", filepath.Dir(dbPath), info.Mode().Perm())
} Prevention
- Create the store directory with mode 0700 only
- Set a restrictive umask (077) for the engine process
- Move the store out of world-writable locations like /tmp
- Audit tools (backup, security scanners) that rewrite directory permissions
When it happens
Trigger: validateSQLiteParentSecurity rejects the parent directory's mode/ownership — typically because the directory became world- or group-writable (loose mode) between open and this operation, or was created with insecure permissions.
Common situations: A backup/restore tool resets directory modes to 0777; umask misconfiguration created ~/.caveman as 0777; a shared tmp directory was configured as the store location; security scanners 'fixed' permissions to something the validator also rejects.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- sqlite parent is group/world writable
- file changed while opening
- file changed while securing
- inspect sqlite parent ACL
- refusing non-regular file
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/705035da6648cfcf.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store_generation.go:56
return files, nil
}
parent := filepath.Dir(path)
resolved, err := filepath.EvalSymlinks(parent)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return files, fmt.Errorf("%w: %w: inspect database parent: %v", ErrStorageChanged, errStorageUnverifiable, err)
}
if err != nil || resolved != parent {
return files, fmt.Errorf("%w: database parent changed", ErrStorageChanged)
}
info, err := os.Stat(parent)
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, nilView on GitHub (pinned to 3ee70a1026)