{"record":{"id":"b26e15ca93fa60ae","repo":"JuliusBrussee/caveman","slug":"secure-sqlite-sidecar-q-w","errorCode":null,"errorMessage":"secure sqlite sidecar %q: %w","messagePattern":"secure sqlite sidecar %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":312,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"resolve sqlite parent %q: %w\", parent, err)\n\t}\n\tparentInfo, err := os.Stat(resolvedParent)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"inspect sqlite parent %q: %w\", resolvedParent, err)\n\t}\n\tif !parentInfo.IsDir() {\n\t\treturn \"\", fmt.Errorf(\"sqlite parent %q must be a directory\", resolvedParent)\n\t}\n\tif err := validateSQLiteParentSecurity(resolvedParent, parentInfo); err != nil {\n\t\treturn \"\", err\n\t}\n\tcanonicalPath := filepath.Join(resolvedParent, filepath.Base(path))\n\tif err := secureSQLiteFile(canonicalPath, true); err != nil {\n\t\treturn \"\", fmt.Errorf(\"secure sqlite %q: %w\", canonicalPath, err)\n\t}\n\tfor _, suffix := range []string{\"-wal\", \"-shm\"} {\n\t\tif err := secureSQLiteFile(canonicalPath+suffix, false); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"secure sqlite sidecar %q: %w\", canonicalPath+suffix, err)\n\t\t}\n\t}\n\treturn canonicalPath, nil\n}\n\nfunc secureSQLiteFiles(path string) error {\n\tif path == \":memory:\" {\n\t\treturn nil\n\t}\n\tif _, err := inspectSQLiteGeneration(path); err != nil {\n\t\treturn err\n\t}\n\tfor _, suffix := range sqliteSuffixes {\n\t\tif err := secureSQLiteFile(path+suffix, false); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L294-L330","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n# root-created sidecars block the app user\n$ sudo rm /var/lib/ccr/recovery.db-wal /var/lib/ccr/recovery.db-shm\n// after\n$ ls -l /var/lib/ccr/ # only recovery.db owned by appuser; Open recreates sidecars","handlingStrategy":"validation","validationCode":"for _, suf := range []string{\"-wal\", \"-shm\"} {\n    fi, err := os.Lstat(dbPath + suf)\n    if err == nil && !fi.Mode().IsRegular() {\n        return fmt.Errorf(\"%s%s is not a regular file\", dbPath, suf)\n    }\n}","typeGuard":null,"tryCatchPattern":"err := ccr.Open(dbPath)\nif err != nil && strings.Contains(err.Error(), \"secure sqlite sidecar\") {\n    os.Remove(dbPath+\"-wal\"); os.Remove(dbPath+\"-shm\") // store must be closed\n    err = ccr.Open(dbPath)\n}","preventionTips":["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"],"tags":["go","sqlite","permissions","wal"],"backgroundTag":"file-write-permission-denied","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}