JuliusBrussee/caveman · error
secure sqlite sidecar
Error message
secure sqlite sidecar %q: %w
What it means
Besides the main database file, PrepareSQLitePathCanonical also hardens the SQLite WAL (-wal) and shared-memory (-shm) sidecar files with secureSQLiteFile. This error wraps failure securing one of those sidecars (which may not yet exist; securing is attempted without create). It indicates a chmod/stat failure on a sidecar file.
Solutions
- Delete the stale -wal and -shm files (with the store closed) and let SQLite recreate them with correct ownership
- chown the sidecars to the current user
- Align on a single run-as user for the engine to avoid mixed ownership
- Verify no other process is concurrently holding the database when the error repeats
Example fix
// before # root-created sidecars block the app user $ sudo rm /var/lib/ccr/recovery.db-wal /var/lib/ccr/recovery.db-shm // after $ ls -l /var/lib/ccr/ # only recovery.db owned by appuser; Open recreates sidecars
Defensive patterns
Strategy: validation
Validate before calling
for _, suf := range []string{"-wal", "-shm"} {
fi, err := os.Lstat(dbPath + suf)
if err == nil && !fi.Mode().IsRegular() {
return fmt.Errorf("%s%s is not a regular file", dbPath, suf)
}
} Try / catch
err := ccr.Open(dbPath)
if err != nil && strings.Contains(err.Error(), "secure sqlite sidecar") {
os.Remove(dbPath+"-wal"); os.Remove(dbPath+"-shm") // store must be closed
err = ccr.Open(dbPath)
} Prevention
- Clean up -wal/-shm leftovers after crashes when the store is closed
- Avoid switching run-as users between runs
- Do not place the store in directories managed by sync tools
When it happens
Trigger: Opening a CCR store after a previous unclean shutdown left -wal/-shm files owned by a different user (commonly root after a sudo run); the sidecar files exist on a filesystem where chmod is not permitted; the sidecar was replaced by something non-regular during the secure pass.
Common situations: Mixed-ownership sidecars after switching between running the engine as root and as a normal user; crash-recovery leftovers in a shared data directory; container user-remapping making previously created sidecars inaccessible.
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
- sqlite parent is group/world writable
- : : inspect database parent
- : : inspect database
- %w: %w: %v
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/b26e15ca93fa60ae.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/store_sqlite.go:312
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 {
return err
}
}
return nilView on GitHub (pinned to 3ee70a1026)