{"record":{"id":"a3cf64bb944bfecb","repo":"getsops/sops","slug":"cannot-stat-gnupghome-w","errorCode":null,"errorMessage":"cannot stat GNUPGHOME: %w","messagePattern":"cannot stat GNUPGHOME: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgp/keysource.go","lineNumber":203,"sourceCode":"\t}\n\treturn os.RemoveAll(d.String())\n}\n\n// Validate ensures the GnuPGHome is a valid GnuPG home directory path.\n// When validation fails, it returns a descriptive reason as error.\nfunc (d GnuPGHome) Validate() error {\n\tif d == \"\" {\n\t\treturn fmt.Errorf(\"empty GNUPGHOME path\")\n\t}\n\tif !filepath.IsAbs(d.String()) {\n\t\treturn fmt.Errorf(\"GNUPGHOME must be an absolute path\")\n\t}\n\tfi, err := os.Lstat(d.String())\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn fmt.Errorf(\"GNUPGHOME does not exist\")\n\t\t}\n\t\treturn fmt.Errorf(\"cannot stat GNUPGHOME: %w\", err)\n\t}\n\tif !fi.IsDir() {\n\t\treturn fmt.Errorf(\"GNUGPHOME is not a directory\")\n\t}\n\tif perm := fi.Mode().Perm(); perm != 0o700 {\n\t\treturn fmt.Errorf(\"GNUPGHOME has invalid permissions: got %#o wanted %#o\", perm, 0o700)\n\t}\n\treturn nil\n}\n\n// String returns the GnuPGHome as a string. It does not Validate.\nfunc (d GnuPGHome) String() string {\n\treturn string(d)\n}\n\n// ApplyToMasterKey configures the GnuPGHome on the provided key if it passes\n// Validate.\nfunc (d GnuPGHome) ApplyToMasterKey(key *MasterKey) {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/pgp/keysource.go#L185-L221","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nexport GNUPGHOME=/root/.gnupg  # run as non-root user\n// after\nexport GNUPGHOME=$HOME/.gnupg && mkdir -p \"$GNUPGHOME\" && chmod 700 \"$GNUPGHOME\"","handlingStrategy":"validation","validationCode":"home := pgp.GnuPGHome(os.Getenv(\"GNUPGHOME\"))\nif err := home.Validate(); err != nil {\n    return fmt.Errorf(\"GNUPGHOME unusable: %w\", err)\n}\n// also verify parent traversal:\nfor dir := filepath.Dir(string(home)); dir != \"/\"; dir = filepath.Dir(dir) {\n    if fi, err := os.Stat(dir); err != nil || fi.Mode().Perm()&0o044 == 0 {\n        return fmt.Errorf(\"cannot traverse %s: %v\", dir, err)\n    }\n}","typeGuard":"func validGnuPGHome(h pgp.GnuPGHome) bool {\n    fi, err := os.Lstat(string(h))\n    return err == nil && fi.IsDir()\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["gnupg","filesystem","permissions"],"backgroundTag":"gnupghome-invalid","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}