{"record":{"id":"004ad3d1e7c7fbed","repo":"JuliusBrussee/caveman","slug":"inspect-sqlite-parent-q-w","errorCode":null,"errorMessage":"inspect sqlite parent %q: %w","messagePattern":"inspect sqlite parent %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_sqlite.go","lineNumber":298,"sourceCode":"func PrepareSQLitePathCanonical(path string) (string, error) {\n\tif path == \":memory:\" {\n\t\treturn path, nil\n\t}\n\tif strings.TrimSpace(path) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"ccr sqlite path is required\")\n\t}\n\tparent := filepath.Dir(path)\n\tabsoluteParent, err := filepath.Abs(parent)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve sqlite parent %q: %w\", parent, err)\n\t}\n\tresolvedParent, err := filepath.EvalSymlinks(absoluteParent)\n\tif err != nil {\n\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}","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_sqlite.go#L280-L316","documentation":"PrepareSQLitePathCanonical resolves the parent directory of the SQLite database path via filepath.EvalSymlinks, and this error wraps any failure from that resolution. It means the library could not canonicalize the parent directory (e.g. it does not exist, is inaccessible, or a symlink loop was found) before opening the CCR SQLite store, so it refuses to proceed rather than opening an unsafe path.","triggerScenarios":"Calling ccr.Open/PrepareSQLitePath with a database path whose parent directory does not exist on disk; the parent path contains a broken symlink; the parent symlink chain forms a loop; or the process lacks permission to traverse a symlinked parent on any platform including Windows.","commonSituations":"A config file points at a data directory that was deleted or never created (e.g. ~/.caveman/ccr removed by a cleanup tool); a docker volume or mount point not yet mounted when the engine starts; running on Windows where EvalSymlinks fails for certain paths; typo in the directory portion of the configured db path.","solutions":["Verify the parent directory of the sqlite path exists; create it with os.MkdirAll before calling Open","Check for broken symlinks in the path (ls -l / readlink -f) and repair or remove them","Ensure the process has execute/traverse permission on every component of the parent path","Fix the configured database path in your engine/store configuration","Run as a user with access to the directory; on Windows confirm the path is a valid NTFS path without a symlink loop"],"exampleFix":"// before\nstore, err := ccr.Open(\"/var/lib/ccr/cache/recovery.db\") // parent missing\n// after\nif err := os.MkdirAll(\"/var/lib/ccr/cache\", 0o700); err != nil { log.Fatal(err) }\nstore, err := ccr.Open(\"/var/lib/ccr/cache/recovery.db\")","handlingStrategy":"validation","validationCode":"func parentExists(dbPath string) error {\n    parent := filepath.Dir(dbPath)\n    if _, err := filepath.EvalSymlinks(parent); err != nil {\n        return fmt.Errorf(\"cannot resolve parent %q: %w\", parent, err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"path, err := ccr.PrepareSQLitePath(dbPath)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) { os.MkdirAll(filepath.Dir(dbPath), 0o700) }\n    return err\n}","preventionTips":["Always os.MkdirAll(filepath.Dir(dbPath), 0o700) before Open","Avoid symlinks in the sqlite store path","Validate configured paths at startup with a fail-fast check","Ensure the run-as user can traverse the full path"],"tags":["go","sqlite","filesystem"],"backgroundTag":"directory-not-found","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"}