{"record":{"id":"9fb6e97e10e21247","repo":"git-ecosystem/git-credential-manager","slug":"failed-to-encrypt-file-0-with-gpg-exit-1-o","errorCode":null,"errorMessage":"Failed to encrypt file '{0}' with gpg. exit={1}, out={2}, err={3}","messagePattern":"Failed to encrypt file '(.+?)' with gpg\\. exit=(.+?), out=(.+?), err=(.+?)","errorType":"exception","errorClass":"Trace2Exception","httpStatus":null,"severity":"error","filePath":"src/Core/Gpg.cs","lineNumber":97,"sourceCode":"            using (var gpg = _processManager.CreateProcess(psi))\n            {\n                if (!gpg.Start(Trace2ProcessClass.Other))\n                {\n                    throw new Trace2Exception(_trace2, \"Failed to start gpg.\");\n                }\n\n                gpg.StandardInput.Write(contents);\n                gpg.StandardInput.Close();\n\n                gpg.WaitForExit();\n\n                if (gpg.ExitCode != 0)\n                {\n                    string stdout = gpg.StandardOutput.ReadToEnd();\n                    string stderr = gpg.StandardError.ReadToEnd();\n                    var format = \"Failed to encrypt file '{0}' with gpg. exit={1}, out={2}, err={3}\";\n                    var message = string.Format(format, path, gpg.ExitCode, stdout, stderr);\n                    throw new Trace2Exception(_trace2, message, format);\n                }\n            }\n        }\n\n        private void PrepareEnvironment(ProcessStartInfo psi)\n        {\n            // If we're in a headless environment over SSH, and we don't have a GPG_TTY\n            // explicitly set, use the SSH_TTY variable for our GPG_TTY.\n            if (!_sessionManager.IsDesktopSession &&\n                !psi.Environment.ContainsKey(\"GPG_TTY\") &&\n                psi.Environment.ContainsKey(\"SSH_TTY\"))\n            {\n                psi.Environment[\"GPG_TTY\"] = psi.Environment[\"SSH_TTY\"];\n            }\n        }\n    }\n}\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/Gpg.cs#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nawait gpg.EncryptFile(filePath); // throws if gpg fails\n// after\nvar check = Process.Start(new ProcessStartInfo(\"gpg\", \"--list-keys\"));\ncheck.WaitForExit();\nif (check.ExitCode != 0)\n    throw new InvalidOperationException(\"gpg keyring not usable; import the required key first.\");\nawait gpg.EncryptFile(filePath);","handlingStrategy":"try-catch","validationCode":"var probe = Process.Start(new ProcessStartInfo(\"gpg\", \"--list-keys\") { RedirectStandardOutput = true });\nprobe.WaitForExit();\nif (probe.ExitCode != 0) throw new InvalidOperationException(\"gpg is not functional in this environment\");","typeGuard":null,"tryCatchPattern":"try\n{\n    gpg.EncryptFile(path);\n}\ncatch (Trace2Exception ex) when (ex.Message.Contains(\"Failed to encrypt file\"))\n{\n    logger.LogError(ex, \"gpg encryption failed; inspect out=/err= in message for the gpg cause\");\n}","preventionTips":["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"],"tags":["gpg","external-process","encryption","csharp"],"backgroundTag":"git-command-failed","analyzedSha":"e8ce762cd04b4100ae637b5fbf39ef9d0a96561e","analyzedAt":"2026-09-11T17:15:08.753Z","contentChangedAt":"2026-09-11T17:15:08.753Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}