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 passes

View on GitHub (pinned to 13442bb981)

Solutions

  1. Create the directory before use (os.MkdirAll(d.String(), 0o700)) or obtain it via NewGnuPGHome().
  2. Do not reuse a GnuPGHome after calling Cleanup; create a fresh one per operation.
  3. Verify the absolute path exists: `ls -ld <path>` and fix the configured value.
  4. 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

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


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/a17aa11c714a6b37. Report an issue: GitHub.