git-ecosystem/git-credential-manager · error · Exception
Cannot find GPG ID in password store at
Error message
Cannot find GPG ID in password store at '{StoreRoot}'; run `pass init <gpg-id>` to initialize the store. What it means
GetGpgId walks up from a password-store path looking for a .gpg-id file whose contents identify the GPG key used to encrypt credentials. If it reaches the store root (or filesystem root) without finding one, it throws because the `pass` store was never initialized. This exception prevents encrypting credentials with an unknown key.
Solutions
- Initialize the store: `pass init <your-gpg-id>` (writes .gpg-id at the store root).
- If the store exists elsewhere, set the credential store root path configuration to the directory containing .gpg-id.
- Verify a .gpg-id file exists and is non-empty: `cat ~/.password-store/.gpg-id`.
- If you don't use pass, switch credential.credentialStore to cache, plaintext, or another supported store.
Example fix
// before // store directory created manually, no .gpg-id mkdir -p ~/.password-store // after pass init user@example.com # creates ~/.password-store/.gpg-id
Defensive patterns
Strategy: validation
Validate before calling
string FindGpgId(string storeRoot) {
var p = Path.Combine(storeRoot, ".gpg-id");
if (!File.Exists(p)) throw new InvalidOperationException(
$"{storeRoot} is not initialized; run: pass init <gpg-id>");
if (string.IsNullOrWhiteSpace(File.ReadAllText(p).Trim()))
throw new InvalidOperationException(".gpg-id is empty; re-run: pass init <gpg-id>");
return p;
} Try / catch
try { store.Save(cred); }
catch (Exception ex) when (ex.Message.Contains("Cannot find GPG ID"))
{ Console.Error.WriteLine("Run 'pass init <gpg-id>' first."); return 1; } Prevention
- Always create a pass store with `pass init <gpg-id>`, never by hand with mkdir.
- Add a startup check for the presence of .gpg-id before configuring the gpg credential store.
- When sharing stores across machines, ensure .gpg-id is committed/synced with the store.
- Verify GPG key availability: gpg --list-keys <gpg-id>.
When it happens
Trigger: Using the GpgPassCredentialStore ('gpg'/'pass' credential store) against a directory that lacks a .gpg-id file anywhere between the credential path and StoreRoot — i.e. `pass init <gpg-id>` was never run for that store.
Common situations: Manually creating the password-store directory instead of running `pass init`; setting credentialStore=gpg but pointing at an empty or wrong directory; cloning a pass store without the .gpg-id file; typo'd credentialStoreRootPath.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Can only use the ' ' credential store on POSIX systems. See…
- GPG executable does not exist with path
- Bitbucket DC OAuth Client ID must be defined
- Bitbucket DC OAuth Client Secret must be defined
- RemoteUri must be defined to generate Bitbucket DC OAuth2…
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/a84fc927a7555bec.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Interop/Posix/GpgPassCredentialStore.cs:52
if (FileSystem.FileExists(gpgIdPath))
{
using (var stream = FileSystem.OpenFileStream(gpgIdPath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var reader = new StreamReader(stream))
{
return reader.ReadLine();
}
}
// Stop after checking the store root
if (FileSystem.IsSamePath(dir, StoreRoot))
{
break;
}
dir = Path.GetDirectoryName(dir);
}
throw new Exception($"Cannot find GPG ID in password store at '{StoreRoot}'; run `pass init <gpg-id>` to initialize the store.");
}
protected override bool TryDeserializeCredential(string path, out FileCredential credential)
{
string text = _gpg.DecryptFile(path);
int line1Idx = text.IndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase);
if (line1Idx > 0)
{
// Password is the first line
string password = text.Substring(0, line1Idx);
// All subsequent lines are metadata/attributes
string attrText = text.Substring(line1Idx + Environment.NewLine.Length);
using var attrReader = new StringReader(attrText);
IDictionary<string, string> attrs = attrReader.ReadDictionary(StringComparer.OrdinalIgnoreCase);
// Account is optionalView on GitHub (pinned to e8ce762cd0)