{"record":{"id":"705035da6648cfcf","repo":"JuliusBrussee/caveman","slug":"w-w-v","errorCode":null,"errorMessage":"%w: %w: %v","messagePattern":"%w: %w: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/ccr/store_generation.go","lineNumber":56,"sourceCode":"\t\treturn files, nil\n\t}\n\tparent := filepath.Dir(path)\n\tresolved, err := filepath.EvalSymlinks(parent)\n\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\treturn files, fmt.Errorf(\"%w: %w: inspect database parent: %v\", ErrStorageChanged, errStorageUnverifiable, err)\n\t}\n\tif err != nil || resolved != parent {\n\t\treturn files, fmt.Errorf(\"%w: database parent changed\", ErrStorageChanged)\n\t}\n\tinfo, err := os.Stat(parent)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn files, fmt.Errorf(\"%w: database parent changed\", ErrStorageChanged)\n\t}\n\tif err != nil {\n\t\treturn files, fmt.Errorf(\"%w: %w: inspect database parent: %v\", ErrStorageChanged, errStorageUnverifiable, err)\n\t}\n\tif err := validateSQLiteParentSecurity(parent, info); err != nil {\n\t\treturn files, fmt.Errorf(\"%w: %w: %v\", ErrStorageChanged, errStorageUnverifiable, err)\n\t}\n\tfor i, suffix := range sqliteSuffixes {\n\t\tinfo, err := inspectSQLiteFile(path + suffix)\n\t\tif errors.Is(err, os.ErrNotExist) && i != 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn files, fmt.Errorf(\"%w: inspect database%s: %v\", ErrStorageChanged, suffix, err)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn files, fmt.Errorf(\"%w: %w: inspect database%s: %v\", ErrStorageChanged, errStorageUnverifiable, suffix, err)\n\t\t}\n\t\tif !info.Mode().IsRegular() {\n\t\t\treturn files, fmt.Errorf(\"%w: refusing non-regular database%s\", ErrStorageChanged, suffix)\n\t\t}\n\t\tfiles[i] = info\n\t}\n\treturn files, nil","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/ccr/store_generation.go#L38-L74","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nos.MkdirAll(dataDir, 0o777)\n// after\nos.MkdirAll(dataDir, 0o700)","handlingStrategy":"validation","validationCode":"info, err := os.Stat(filepath.Dir(dbPath))\nif err == nil && info.Mode().Perm()&0o077 != 0 {\n    return fmt.Errorf(\"store dir %s too open: %v\", filepath.Dir(dbPath), info.Mode().Perm())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["go","sqlite","permissions","security","storage-identity"],"backgroundTag":"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"}