git-ecosystem/git-credential-manager · error · Trace2Exception

Failed to encrypt file

Error message

Failed to encrypt file '{0}' with gpg. exit={1}, out={2}, err={3}

What it means

Gpg.EncryptFile shells out to the external 'gpg' binary to encrypt a file; if the process exits with a non-zero exit code, the library wraps stdout/stderr in this exception (a Trace2Exception so the failure is also traced). It signals that the external gpg invocation failed, not a bug in the library itself. The gpg output is embedded in the message to aid diagnosis.

Solutions

  1. Read the 'err=' portion of the message — it contains gpg's stderr with the actual cause (missing key, bad passphrase, etc.)
  2. Run the equivalent gpg command manually (e.g. gpg --encrypt -r <recipient>) to reproduce and fix the key/config issue
  3. Verify the required public key exists: gpg --list-keys, and import it if missing (gpg --import)
  4. Ensure gpg can run non-interactively (set GPG_TTY, use --batch/--pinentry-mode loopback where appropriate)

Example fix

// before
await gpg.EncryptFile(filePath); // throws if gpg fails
// after
var check = Process.Start(new ProcessStartInfo("gpg", "--list-keys"));
check.WaitForExit();
if (check.ExitCode != 0)
    throw new InvalidOperationException("gpg keyring not usable; import the required key first.");
await gpg.EncryptFile(filePath);
Defensive patterns

Strategy: try-catch

Validate before calling

var probe = Process.Start(new ProcessStartInfo("gpg", "--list-keys") { RedirectStandardOutput = true });
probe.WaitForExit();
if (probe.ExitCode != 0) throw new InvalidOperationException("gpg is not functional in this environment");

Try / catch

try
{
    gpg.EncryptFile(path);
}
catch (Trace2Exception ex) when (ex.Message.Contains("Failed to encrypt file"))
{
    logger.LogError(ex, "gpg encryption failed; inspect out=/err= in message for the gpg cause");
}

Prevention

When it happens

Trigger: Calling Gpg.EncryptFile(path) when the spawned gpg process returns a non-zero exit code — e.g. missing/invalid recipient key, no secret key available, bad keyring permissions, or gpg not configured for the user.

Common situations: Commit signing/encryption setups in environments without a gpg keyring (CI containers), GPG_HOME pointing at the wrong home, expired or untrusted keys, or gpg pinentry prompts failing in non-interactive terminals.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11). Data as JSON: /api/errors/9fb6e97e10e21247. Report an issue: GitHub.

Appendix: source

Thrown at src/Core/Gpg.cs:97

            using (var gpg = _processManager.CreateProcess(psi))
            {
                if (!gpg.Start(Trace2ProcessClass.Other))
                {
                    throw new Trace2Exception(_trace2, "Failed to start gpg.");
                }

                gpg.StandardInput.Write(contents);
                gpg.StandardInput.Close();

                gpg.WaitForExit();

                if (gpg.ExitCode != 0)
                {
                    string stdout = gpg.StandardOutput.ReadToEnd();
                    string stderr = gpg.StandardError.ReadToEnd();
                    var format = "Failed to encrypt file '{0}' with gpg. exit={1}, out={2}, err={3}";
                    var message = string.Format(format, path, gpg.ExitCode, stdout, stderr);
                    throw new Trace2Exception(_trace2, message, format);
                }
            }
        }

        private void PrepareEnvironment(ProcessStartInfo psi)
        {
            // If we're in a headless environment over SSH, and we don't have a GPG_TTY
            // explicitly set, use the SSH_TTY variable for our GPG_TTY.
            if (!_sessionManager.IsDesktopSession &&
                !psi.Environment.ContainsKey("GPG_TTY") &&
                psi.Environment.ContainsKey("SSH_TTY"))
            {
                psi.Environment["GPG_TTY"] = psi.Environment["SSH_TTY"];
            }
        }
    }
}

View on GitHub (pinned to e8ce762cd0)