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

GPG_TTY is not set; add `export GPG_TTY=$(tty)` to your…

Error message

GPG_TTY is not set; add `export GPG_TTY=$(tty)` to your profile.
See {Constants.HelpUrls.GcmCredentialStores} for more information.

What it means

When using the '{gpg}' (pass) credential store on a non-desktop (headless) POSIX session, GCM needs a TTY for GPG pinentry. It throws this Exception if neither GPG_TTY nor SSH_TTY is set in the environment and there is no desktop session, because GPG would otherwise be unable to prompt for the passphrase.

Solutions

  1. Add `export GPG_TTY=$(tty)` to the shell profile or the job's environment before invoking git.
  2. For non-interactive contexts, set GPG_TTY explicitly (e.g. GPG_TTY=$(tty) || true) and use loopback pinentry with a passphrase file via GCM options.
  3. Run gpg-agent with a cached passphrase so pinentry is never required in headless jobs.

Example fix

// before (CI step)
- run: git push
// after
- run: |
    export GPG_TTY=$(tty)
    git push
Defensive patterns

Strategy: validation

Validate before calling

if (!process.env.GPG_TTY && !process.env.SSH_TTY && !process.env.DISPLAY && usingGpgStore) {
  process.env.GPG_TTY = execSync('tty').toString().trim();
}

Prevention

When it happens

Trigger: store=gpg with IsDesktopSession=false and no GPG_TTY/SSH_TTY variable — e.g. SSH into a server (without -t / agent forwarding env), cron/systemd jobs, or containers running git operations.

Common situations: Cron jobs or systemd timers performing git fetch/push with pass; CI containers using GPG-encrypted credential files; SSH non-interactive sessions missing tty export.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src/Core/CredentialStore.cs:295

            {
                var message = $"Can only use the '{StoreNames.Gpg}' credential store on POSIX systems.";
                _context.Trace2.WriteError(message);
                throw new Exception(message + Environment.NewLine +
                                    $"See {Constants.HelpUrls.GcmCredentialStores} for more information."
                );
            }

            execPath = GetGpgPath();

            // If we are in a headless environment, and don't have the GPG_TTY or SSH_TTY
            // variables set, then error - we need a TTY device path for pin-entry to work headless.
            if (!_context.SessionManager.IsDesktopSession &&
                !_context.Environment.Variables.ContainsKey("GPG_TTY") &&
                !_context.Environment.Variables.ContainsKey("SSH_TTY"))
            {
                var message = "GPG_TTY is not set; add `export GPG_TTY=$(tty)` to your profile.";
                _context.Trace2.WriteError(message);
                throw new Exception(message + Environment.NewLine +
                                    $"See {Constants.HelpUrls.GcmCredentialStores} for more information."
                );
            }

            // Check for a redirected pass store location
            if (!_context.Settings.TryGetSetting(
                GpgPassCredentialStore.PasswordStoreDirEnvar,
                Constants.GitConfiguration.Credential.SectionName,
                Constants.GitConfiguration.Credential.GpgPassStorePath,
                out storeRoot))
            {
                // Use default store root at ~/.password-store
                storeRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".password-store");
            }

        }

        private void ValidateCredentialCache(out string options)

View on GitHub (pinned to e8ce762cd0)