getsops/sops · error
GNUPGHOME does not exist
Error message
GNUPGHOME does not exist
What it means
GnuPGHome.Validate uses os.Lstat to check the path; if it does not exist, this error is returned. ImportContext, Cleanup, and ApplyToMasterKey all surface it via their own wrappers. Note Validate allows a nonexistent directory? No - existence is required here (only Lstat success proceeds to the IsDir check), so the home must already exist on disk.
Source
Thrown at pgp/keysource.go:201
if err := d.Validate(); err != nil {
return err
}
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 passesView on GitHub (pinned to 13442bb981)
Solutions
- Create the directory before use (os.MkdirAll(d.String(), 0o700)) or obtain it via NewGnuPGHome().
- Do not reuse a GnuPGHome after calling Cleanup; create a fresh one per operation.
- Verify the absolute path exists: `ls -ld <path>` and fix the configured value.
- If parallel code may delete it, serialize access or check existence with os.Lstat before use.
Example fix
// before
home := pgp.GnuPGHome("/tmp/stale-gnupg") // deleted earlier by Cleanup
home.Import(key)
// after
home, err := pgp.NewGnuPGHome()
if err != nil { return err }
defer home.Cleanup() Defensive patterns
Strategy: validation
Validate before calling
// Go
func ensureExists(home pgp.GnuPGHome) error {
if _, err := os.Lstat(home.String()); err != nil {
if os.IsNotExist(err) { return os.MkdirAll(home.String(), 0o700) }
return err
}
return nil
} Type guard
func homeExists(home pgp.GnuPGHome) bool { fi, err := os.Lstat(home.String()); return err == nil && fi.IsDir() } Try / catch
// Go
if err := home.Validate(); err != nil && strings.Contains(err.Error(), "GNUPGHOME does not exist") {
// recreate the home once
nh, nerr := pgp.NewGnuPGHome(); if nerr != nil { return nerr }
home = nh
} Prevention
- Treat GnuPGHome as single-use: one lifecycle (create, import, cleanup), never reuse
- Create missing directories with os.MkdirAll 0700 before use
- Avoid hardcoded /tmp paths that external cleanup jobs may delete
- Call Validate() before Import/Cleanup to catch deletion early
When it happens
Trigger: Pointing GnuPGHome at a path that was never created, at a temp directory already removed by Cleanup, or a deleted cache/tmp location, then calling Import/ImportContext, Cleanup, or ApplyToMasterKey.
Common situations: Reusing a GnuPGHome after Cleanup succeeded; hardcoding a GNUPGHOME path that was removed; race where another process deleted the temp dir; typo in an absolute path.
Related errors
- failed to create new GnuPG home: %w
- cannot import armored key data into GnuPG keyring: %w
- cannot read armored key data from file: %w
- empty GNUPGHOME path
- GNUPGHOME must be an absolute path
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/a17aa11c714a6b37.
Report an issue: GitHub.