JuliusBrussee/caveman · error
secure sqlite
Error message
secure sqlite %q: %w
What it means
PrepareSQLitePathCanonical hardens the canonical sqlite file (and its WAL/SHM sidecars) via secureSQLiteFile, which enforces regular-file type and restrictive permissions (e.g. chmod 0600). This error wraps any failure of that hardening step, such as permission errors changing the file mode or I/O failures statting/chmodding the database file.
Solutions
- chown the database file (and -wal/-shm sidecars) to the user running the process, or delete them and let Open recreate them
- Move the store to a local filesystem that supports POSIX permissions
- Check directory write permission for creating/securing new files (ls -ld)
- Ensure the filesystem is mounted read-write, not read-only
Example fix
// before sudo chown root /var/lib/ccr/recovery.db // after sudo chown appuser:appuser /var/lib/ccr/recovery.db*
Defensive patterns
Strategy: validation
Validate before calling
func canSecure(dbPath string) error {
dir := filepath.Dir(dbPath)
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() { return err }
f, err := os.OpenFile(filepath.Join(dir, ".ccr-write-test"), os.O_CREATE|os.O_WRONLY, 0o600)
if err != nil { return err }
f.Close(); return os.Remove(filepath.Join(dir, ".ccr-write-test"))
} Try / catch
err := ccr.Open(dbPath)
if err != nil && strings.Contains(err.Error(), "secure sqlite") {
return fmt.Errorf("check ownership/permissions of %s and its sidecars: %w", dbPath, err)
} Prevention
- Run the engine consistently as the same user
- Keep the store on a local POSIX filesystem, not NFS/FAT
- Never run once as root against a user-owned store directory
When it happens
Trigger: Opening a CCR sqlite store whose database file exists but cannot be chmod'd (owned by another user or on a filesystem that does not support chmod, e.g. some network mounts); the file cannot be created/secured because the directory is read-only; secureSQLiteFile's internal Lstat/Chmod call fails for any reason.
Common situations: Database file created previously by root and now opened as an unprivileged user; sqlite db placed on an NFS/SMB or FAT mount where chmod fails or is unsupported; read-only container rootfs while trying to create the db.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
Related errors
- secure sqlite sidecar
- sqlite parent is group/world writable
- : : inspect database parent
- %w: %w: %v
- budget is below CCR storage minimum
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/5aef0877ec5d41ac.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store_sqlite.go:308
return "", fmt.Errorf("resolve sqlite parent %q: %w", parent, err)
}
resolvedParent, err := filepath.EvalSymlinks(absoluteParent)
if err != nil {
return "", fmt.Errorf("resolve sqlite parent %q: %w", parent, err)
}
parentInfo, err := os.Stat(resolvedParent)
if err != nil {
return "", fmt.Errorf("inspect sqlite parent %q: %w", resolvedParent, err)
}
if !parentInfo.IsDir() {
return "", fmt.Errorf("sqlite parent %q must be a directory", resolvedParent)
}
if err := validateSQLiteParentSecurity(resolvedParent, parentInfo); err != nil {
return "", err
}
canonicalPath := filepath.Join(resolvedParent, filepath.Base(path))
if err := secureSQLiteFile(canonicalPath, true); err != nil {
return "", fmt.Errorf("secure sqlite %q: %w", canonicalPath, err)
}
for _, suffix := range []string{"-wal", "-shm"} {
if err := secureSQLiteFile(canonicalPath+suffix, false); err != nil {
return "", fmt.Errorf("secure sqlite sidecar %q: %w", canonicalPath+suffix, err)
}
}
return canonicalPath, nil
}
func secureSQLiteFiles(path string) error {
if path == ":memory:" {
return nil
}
if _, err := inspectSQLiteGeneration(path); err != nil {
return err
}
for _, suffix := range sqliteSuffixes {
if err := secureSQLiteFile(path+suffix, false); err != nil {View on GitHub (pinned to 3ee70a1026)