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

  1. Initialize the store: `pass init <your-gpg-id>` (writes .gpg-id at the store root).
  2. If the store exists elsewhere, set the credential store root path configuration to the directory containing .gpg-id.
  3. Verify a .gpg-id file exists and is non-empty: `cat ~/.password-store/.gpg-id`.
  4. 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

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


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 optional

View on GitHub (pinned to e8ce762cd0)