JuliusBrussee/caveman · error
sqlite parent has no restrictive DACL
Error message
sqlite parent %q has no restrictive DACL
What it means
engine/ccr on Windows treats a parent directory with no DACL as unsafe for the SQLite database: with no discretionary ACL there is no way to prove other users cannot modify the directory, so it fails closed with 'sqlite parent %q has no restrictive DACL' rather than risk database replacement.
Solutions
- Point the store at a local NTFS directory under the user's profile (%LOCALAPPDATA%) which always has a DACL
- Apply an explicit restrictive ACL to the directory: icacls <dir> /inheritance:r /grant:r "%USERNAME%":(OI)(CI)F
- Confirm the directory is on NTFS and not a network share; move the data off unsupported filesystems
Example fix
// before
store, _ := engine.OpenCCRStore(os.TempDir() + "\\ccr\\db.sqlite") // exotic temp mount, no DACL
// after
os.MkdirAll(filepath.Join(os.Getenv("LOCALAPPDATA"), "myapp"), 0o700)
store, _ := engine.OpenCCRStore(filepath.Join(os.Getenv("LOCALAPPDATA"), "myapp", "db.sqlite")) Defensive patterns
Strategy: validation
Validate before calling
// pre-check: directory must have a DACL
sd, _ := windows.GetNamedSecurityInfo(parentDir, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION)
if sd != nil {
if dacl, _, err := sd.DACL(); err != nil || dacl == nil {
return fmt.Errorf("%s has no DACL; apply one via icacls", parentDir)
}
} Prevention
- Place databases in user-profile NTFS directories, which always carry a DACL
- Apply explicit ACLs (icacls <dir> /inheritance:r /grant:r user:F) to custom data dirs
- Verify volume type before choosing a storage location for app data
When it happens
Trigger: validateSQLiteParentSecurity queries the parent directory's security descriptor and descriptor.DACL() returns nil (or errors) — the directory exists but carries no DACL, typically on volumes or share configurations that don't apply Windows ACLs.
Common situations: Directories created on FAT/exFAT drives, some network shares, or by tools that strip ACLs; freshly mounted volumes before ACL inheritance is applied; unusual temp locations set via environment overrides.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- inspect sqlite parent ACL
- sqlite parent has no security descriptor
- sqlite parent grants broad Windows write access
- sqlite parent is group/world writable
- : database parent changed
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/ca81f50b42ee58d7.
Report an issue: GitHub.
Appendix: source
Thrown at engine/ccr/sqlite_parent_security_windows.go:27
"golang.org/x/sys/windows"
)
func validateSQLiteParentSecurity(path string, _ os.FileInfo) error {
descriptor, err := windows.GetNamedSecurityInfo(
path,
windows.SE_FILE_OBJECT,
windows.DACL_SECURITY_INFORMATION,
)
if err != nil {
return fmt.Errorf("inspect sqlite parent ACL %q: %w", path, err)
}
if descriptor == nil {
return fmt.Errorf("sqlite parent %q has no security descriptor", path)
}
dacl, _, err := descriptor.DACL()
if err != nil || dacl == nil {
return fmt.Errorf("sqlite parent %q has no restrictive DACL", path)
}
broad, err := windowsACLGrantsBroadWrite(dacl)
if err != nil {
return fmt.Errorf("inspect sqlite parent ACL %q: %w", path, err)
}
if broad {
return fmt.Errorf("sqlite parent %q grants broad Windows write access", path)
}
return nil
}
func windowsACLGrantsBroadWrite(dacl *windows.ACL) (bool, error) {
broadSIDs := make([]*windows.SID, 0, 4)
for _, sidType := range []windows.WELL_KNOWN_SID_TYPE{
windows.WinWorldSid,
windows.WinAuthenticatedUserSid,
windows.WinBuiltinUsersSid,
windows.WinBuiltinGuestsSid,View on GitHub (pinned to 3ee70a1026)