restic/restic · error
error converting bytes to security descriptor: %w
Error message
error converting bytes to security descriptor: %w
What it means
During restore, setSecurityDescriptor first converts the stored descriptor bytes back to a struct with securityDescriptorBytesToStruct; this error wraps that conversion failing. The bytes come from the snapshot's GenericAttributes, so failure means the stored blob is not a valid self-relative security descriptor. This points to snapshot data corruption or an encoding mismatch rather than a rights problem (rights are checked later during the set calls).
Source
Thrown at internal/fs/sd_windows.go:77
}
sdBytes, err := securityDescriptorStructToBytes(sd)
if err != nil {
return nil, fmt.Errorf("convert security descriptor to bytes failed: %w", err)
}
return &sdBytes, nil
}
// setSecurityDescriptor sets the SecurityDescriptor for the file at the specified path.
// This needs admin permissions or SeRestorePrivilege, SeSecurityPrivilege and SeTakeOwnershipPrivilege
// for setting the full SD.
// If there are no admin permissions/required privileges, only the DACL from the SD can be set and
// owner and group will be set based on the current user.
func setSecurityDescriptor(filePath string, securityDescriptor *[]byte) error {
// Set the security descriptor on the file
sd, err := securityDescriptorBytesToStruct(*securityDescriptor)
if err != nil {
return fmt.Errorf("error converting bytes to security descriptor: %w", err)
}
owner, _, err := sd.Owner()
if err != nil {
//Do not set partial values.
owner = nil
}
group, _, err := sd.Group()
if err != nil {
//Do not set partial values.
group = nil
}
dacl, _, err := sd.DACL()
if err != nil {
//Do not set partial values.
dacl = nil
}
sacl, _, err := sd.SACL()View on GitHub (pinned to a80be1478a)
Solutions
- Run `restic check --read-data` on the repository to detect corruption.
- Verify which restic version created the snapshot (`restic snapshots --json`) and restore with a current build.
- If only ACLs are affected, restore without them and re-apply permissions from a known-good source (icacls /restore).
- If corruption is confirmed, restore from an older healthy snapshot.
Defensive patterns
Strategy: validation
Validate before calling
import "golang.org/x/sys/windows"
// validate stored SD bytes before restore-time conversion:
func validSecurityDescriptorBytes(b []byte) bool {
if len(b) == 0 {
return false
}
// self-relative SD must start with revision 1 and the SE_SELF_RELATIVE (0x8000) flag
return b[0] == 1 && b[2] == 0x80 && b[3] == 0x00
} Try / catch
if err := setSecurityDescriptor(path, sdBytes); err != nil {
if strings.Contains(err.Error(), "converting bytes to security descriptor") {
// stored blob invalid: corruption indicator — run restic check, skip ACL for this file
warnf("stored ACL for %s is invalid: %v", path, err)
} else {
warnf("ACL restore for %s: %v", path, err)
}
} Prevention
- Run `restic check --read-data` periodically to catch corruption early.
- Restore with a restic version compatible with the snapshot's creator.
- Keep a secondary copy of critical repos on healthy storage.
When it happens
Trigger: The SecurityDescriptor blob in the snapshot is truncated or bit-flipped (repo corruption, failing disk); the snapshot was created by a restic version or tool that stored the field differently; the raw bytes pass JSON decoding but fail ConvertStringSecurityDescriptorToSecurityDescriptor/LocalAlloc validation.
Common situations: Restoring from a repo on deteriorating media without prior check runs; snapshots migrated between repos with faulty tooling; very old snapshots after format evolution.
Related errors
- could not get security descriptor control flags: %w
- error parsing generic attribute for: %s : %v
- error restoring security descriptor for: %s : %v
- securityDescriptor (%d) smaller than expected (%d): %w
- failed to restore timestamp of %q: %w
AI-assisted analysis of restic/restic@a80be1478a (2026-08-15).
Data as JSON: /api/errors/2ef536fc5e4d56d2.
Report an issue: GitHub.