getsops/sops · error
GNUPGHOME has invalid permissions: got %#o wanted %#o
Error message
GNUPGHOME has invalid permissions: got %#o wanted %#o
What it means
GnuPGHome.Validate() enforces that the GNUPGHOME directory has exactly permission bits 0700 (owner read/write/execute, no group/other access). If the mode differs, it returns this error with the got/wanted octal values. gpg itself refuses to operate on a permissive home directory, so sops rejects it up front.
Source
Thrown at pgp/keysource.go:209
func (d GnuPGHome) Validate() error {
if d == "" {
return fmt.Errorf("empty GNUPGHOME path")
}
if !filepath.IsAbs(d.String()) {
return fmt.Errorf("GNUPGHOME must be an absolute path")
}
fi, err := os.Lstat(d.String())
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("GNUPGHOME does not exist")
}
return fmt.Errorf("cannot stat GNUPGHOME: %w", err)
}
if !fi.IsDir() {
return fmt.Errorf("GNUGPHOME is not a directory")
}
if perm := fi.Mode().Perm(); perm != 0o700 {
return fmt.Errorf("GNUPGHOME has invalid permissions: got %#o wanted %#o", perm, 0o700)
}
return nil
}
// String returns the GnuPGHome as a string. It does not Validate.
func (d GnuPGHome) String() string {
return string(d)
}
// ApplyToMasterKey configures the GnuPGHome on the provided key if it passes
// Validate.
func (d GnuPGHome) ApplyToMasterKey(key *MasterKey) {
if err := d.Validate(); err == nil {
key.gnuPGHomeDir = d.String()
}
}
// DisableOpenPGP disables encrypt and decrypt operations using OpenPGP.View on GitHub (pinned to 13442bb981)
Solutions
- chmod 700 on the directory: chmod 700 "$GNUPGHOME"
- Recreate the directory with strict perms: rm -rf and mkdir -p + chmod 700
- In CI, avoid mounting GNUPGHOME from a volume that forces group/other bits; copy into a fresh 0700 dir instead
- Call pgp.GnuPGHome(path).Validate() before use and surface the got/wanted message to the operator
Example fix
// before os.MkdirAll(gnupgHome, 0o755) // after os.MkdirAll(gnupgHome, 0o700) // and chmod 700 if it pre-existed with lax perms
Defensive patterns
Strategy: validation
Validate before calling
if err := pgp.GnuPGHome(path).Validate(); err != nil {
// message includes got/wanted octal perms; surface it
log.Fatal(err)
}
// proactively repair:
if fi, err := os.Stat(path); err == nil && fi.IsDir() && fi.Mode().Perm() != 0o700 {
os.Chmod(path, 0o700)
} Type guard
func hasSafeGnuPGPerms(h pgp.GnuPGHome) bool {
fi, err := os.Stat(string(h))
return err == nil && fi.IsDir() && fi.Mode().Perm() == 0o700
} Prevention
- chmod 700 after any mkdir of GNUPGHOME, including provisioning scripts
- Watch for volumes/mounts (tmpfs, bind mounts, Windows shares) that alter permission bits
- Never share one GNUPGHOME between users; give each service its own 0700 home
- Include a perms check in CI setup steps before running sops
When it happens
Trigger: ImportContext, Cleanup, or ApplyToMasterKey on a GnuPGHome whose directory mode is anything other than 0700 (e.g. 0755 after mkdir without chmod, or 0777 from a shared/tmpfs location).
Common situations: Created the directory with umask 022 leaving 0755; copied a home dir with cp preserving lax perms; running on Windows/CI mounts where perms translate oddly; group-shared GNUPGHOME.
Related errors
- cannot stat GNUPGHOME: %w
- failed to read '%s': %w
- failed to open %s file: %w
- failed to open file: %w
- failed to fetch Azure Key to retrieve key version: %w
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/0f047a0f5cb3b591.
Report an issue: GitHub.