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
- Read the 'err=' portion of the message — it contains gpg's stderr with the actual cause (missing key, bad passphrase, etc.)
- Run the equivalent gpg command manually (e.g. gpg --encrypt -r <recipient>) to reproduce and fix the key/config issue
- Verify the required public key exists: gpg --list-keys, and import it if missing (gpg --import)
- 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
- Verify the recipient public key exists in the keyring before encrypting
- Ensure gpg works non-interactively (GPG_TTY, loopback pinentry) in CI/containers
- Log gpg stderr on failure — the exception already embeds it; parse 'err=' for the root cause
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
- Must specify at least one AuthenticationModes
- Can only use the ' ' credential store on POSIX systems. See…
- GPG_TTY is not set; add `export GPG_TTY=$(tty)` to your…
- GPG executable does not exist with path
- Argument cannot be empty or white space.
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)