getsops/sops · error
cannot stat GNUPGHOME: %w
Error message
cannot stat GNUPGHOME: %w
What it means
GnuPGHome.Validate() calls os.Lstat on the GNUPGHOME path and wraps any stat error that is not ENOENT with this message. It means the path exists per some earlier check but cannot be stat'd — typically a permissions problem on a parent directory, a dangling symlink, or an I/O error. The library throws it because sops needs to verify the GnuPG home directory and its 0700 permissions before importing keys or running gpg.
Source
Thrown at pgp/keysource.go:203
}
return os.RemoveAll(d.String())
}
// Validate ensures the GnuPGHome is a valid GnuPG home directory path.
// When validation fails, it returns a descriptive reason as error.
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) {View on GitHub (pinned to 13442bb981)
Solutions
- Check the wrapped cause (%w) with ls -la on the path and each parent directory
- Fix permissions so the invoking user can traverse all parent directories (chmod +x on parents)
- Replace dangling symlinks or recreate the GNUPGHOME directory with mkdir -p and chmod 700
- Avoid pointing GNUPGHOME at another user's directory; use your own or a shared service account
Example fix
// before export GNUPGHOME=/root/.gnupg # run as non-root user // after export GNUPGHOME=$HOME/.gnupg && mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME"
Defensive patterns
Strategy: validation
Validate before calling
home := pgp.GnuPGHome(os.Getenv("GNUPGHOME"))
if err := home.Validate(); err != nil {
return fmt.Errorf("GNUPGHOME unusable: %w", err)
}
// also verify parent traversal:
for dir := filepath.Dir(string(home)); dir != "/"; dir = filepath.Dir(dir) {
if fi, err := os.Stat(dir); err != nil || fi.Mode().Perm()&0o044 == 0 {
return fmt.Errorf("cannot traverse %s: %v", dir, err)
}
} Type guard
func validGnuPGHome(h pgp.GnuPGHome) bool {
fi, err := os.Lstat(string(h))
return err == nil && fi.IsDir()
} Prevention
- Always create GNUPGHOME with mkdir -p and chmod 700 before use
- Never point GNUPGHOME at a path under a directory unreadable by the running user
- Call GnuPGHome.Validate() early at startup to fail fast with a clear message
- Avoid symlinks in the GNUPGHOME path
When it happens
Trigger: Calling ImportContext, Cleanup, or ApplyToMasterKey with a GnuPGHome whose path cannot be lstat'ed for a reason other than non-existence (e.g. permission denied on a parent directory, too-long path, dangling symlink).
Common situations: GNUPGHOME set to a path inside a directory the current user cannot read; a symlink pointing nowhere; NFS/EACCES issues; using another user's home directory without read access on intermediate dirs.
Related errors
- failed to create new GnuPG home: %w
- cannot read armored key data from file: %w
- GNUPGHOME does not exist
- GNUGPHOME is not a directory
- GNUPGHOME has invalid permissions: got %#o wanted %#o
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/a3cf64bb944bfecb.
Report an issue: GitHub.