{"record":{"id":"43bfb16dce14da2c","repo":"getsops/sops","slug":"gnugphome-is-not-a-directory","errorCode":null,"errorMessage":"GNUGPHOME is not a directory","messagePattern":"GNUGPHOME is not a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgp/keysource.go","lineNumber":206,"sourceCode":"\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) {\n\tif err := d.Validate(); err == nil {\n\t\tkey.gnuPGHomeDir = d.String()\n\t}","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/pgp/keysource.go#L188-L224","documentation":"GnuPGHome.Validate() checks fi.IsDir() after Lstat; if the path is a regular file, socket, or symlink target that is not a directory, it returns this error (note the typo 'GNUGPHOME'). The library requires GNUPGHOME to be an actual directory because gpg keyrings and sops key imports live inside it.","triggerScenarios":"Calling ImportContext, Cleanup, or ApplyToMasterKey with a GnuPGHome string that points to a non-directory file (e.g. a keyring file, or NewGnuPGHome temp dir that was replaced by a file).","commonSituations":"GNUPGHOME accidentally set to a .gpg keyring file path; a cleanup routine replaced the temp directory with a file; typo in config pointing at a file instead of a directory.","solutions":["Inspect the path: ls -ld \"$GNUPGHOME\" to confirm it is a directory","If it is a file, move it aside and create a directory: mkdir -p <path> && chmod 700 <path>","Correct the GNUPGHOME environment variable or config value to point at the directory, not a keyring file","Call Validate() on the GnuPGHome early in your program to fail fast with a clear message"],"exampleFix":"// before\nhome := pgp.GnuPGHome(\"/home/me/keys.gpg\") // a file\n// after\nhome := pgp.GnuPGHome(\"/home/me/.gnupg\") // a directory, chmod 700","handlingStrategy":"validation","validationCode":"home := pgp.GnuPGHome(cfg.GnuPGHome)\nif err := home.Validate(); err != nil {\n    return fmt.Errorf(\"check GNUPGHOME=%q: %w\", cfg.GnuPGHome, err)\n}","typeGuard":"func isGnuPGDir(h pgp.GnuPGHome) bool {\n    fi, err := os.Stat(string(h))\n    return err == nil && fi.IsDir()\n}","tryCatchPattern":null,"preventionTips":["Point GNUPGHOME at a directory, never at a keyring file like keys.gpg","Validate GnuPGHome before calling Import/ApplyToMasterKey","Use NewGnuPGHome() (which creates a real temp dir) instead of hand-built paths"],"tags":["gnupg","filesystem","configuration"],"backgroundTag":"gnupghome-invalid","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}