Error message
gpg: signing failed: Inappropriate ioctl for device
Also printed as
- [GNUPG:] FAILURE sign 83918950
Git prints it under "error: gpg failed to sign the data". With `--status-fd`, gpg also emits `[GNUPG:] FAILURE sign 83918950` (the numeric GPG error code for this condition).
Git commit signing with GnuPG 2 — pinentry has no terminal
What it means
The signing key is protected by a passphrase, gpg-agent started a terminal pinentry to ask for it, and pinentry could not open a terminal. "Inappropriate ioctl for device" is the operating system's `ENOTTY`: stdin is not a TTY and `GPG_TTY` does not name one. The key and the configuration are fine; only the passphrase prompt failed.
Why it happens
GPG_TTY is not exported
commonGnuPG's documentation requires `export GPG_TTY=$(tty)` in the shell profile. Without it the curses pinentry does not know where to draw the prompt.
Signing from an IDE or GUI client
commonVS Code, JetBrains IDEs and GUI Git clients run git without a terminal. A terminal-only pinentry (`pinentry-curses`, `pinentry-tty`) cannot work there.
Signing in CI with a passphrase-protected key
occasionalThere is no human to type the passphrase. CI needs a dedicated key and a non-interactive way to supply the passphrase.
How to fix it
- 1.
Export GPG_TTY
Add it to your shell profile; refresh the running agent with `updatestartuptty` if it was started from another terminal.
bash # ~/.bashrc or ~/.zshrc export GPG_TTY=$(tty) # if gpg-agent was started before, tell it about the current terminal gpg-connect-agent updatestartuptty /bye - 2.
Use a graphical pinentry
`pinentry-mac`, `pinentry-gnome3` or `pinentry-qt` show a dialog, which also works for IDEs.
bash # macOS (Homebrew): a GUI pinentry works for IDEs and GUI Git clients too brew install pinentry-mac echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf gpgconf --kill gpg-agent - 3.
Loopback pinentry for automation
With `allow-loopback-pinentry`, gpg can read the passphrase from a file. Use a signing-only key dedicated to CI, never a personal key.
bash # CI: a dedicated signing key; passphrase supplied non-interactively via loopback pinentry echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf && gpgconf --kill gpg-agent cat > /usr/local/bin/gpg-ci <<'EOF' #!/bin/sh exec gpg --batch --pinentry-mode loopback --passphrase-file "$GPG_PASSPHRASE_FILE" "$@" EOF chmod +x /usr/local/bin/gpg-ci git config --global gpg.program gpg-ci
Related errors
error: gpg failed to sign the dataGit (commit -S, tag -s, commit.gpgsign) with GnuPGsign_and_send_pubkey: signing failed for RSA "/path/to/key" from agent: agent r…OpenSSH client with an SSH agent (ssh-agent, gpg-agent, 1Password, Secretive, Windows OpenSSH agent)gpg: Can't check signature: No public keyGnuPG (gpg --verify, git verify-commit / verify-tag / log --show-signature)