Error message
ssh: this private key is passphrase protected
Also printed as
- ssh: no key found
"ssh: no key found" (listed as an alias) is a different condition from the same parser: the bytes contain no PEM key block — for example a public key, a PuTTY `.ppk` file or an empty file.
golang.org/x/crypto/ssh (Go) — *ssh.PassphraseMissingError from ssh.ParsePrivateKey
What it means
`ssh.ParsePrivateKey` recognised an encrypted private key and stopped, because it has no passphrase to decrypt it with. The returned `*ssh.PassphraseMissingError` even carries the public key, but signing needs the decrypted private key: call `ssh.ParsePrivateKeyWithPassphrase` or let an SSH agent do the signing. Its sibling "ssh: no key found" means the input contains no recognisable key at all.
Why it happens
The key was created with a passphrase
common`ssh-keygen` prompts for a passphrase and encrypts the key file with it. Interactive OpenSSH asks for it or uses the agent; a Go program has to supply it explicitly.
The tool assumed the agent would unlock the key
occasionalOn a workstation `ssh-add` holds the decrypted key and `ssh` never reads the file. Go code that reads the file directly does not benefit from the agent.
A personal, encrypted key copied into CI
occasionalDeploy keys for automation are usually unencrypted and tightly scoped; reusing a personal encrypted key in CI fails here.
How to fix it
- 1.
Detect the error and supply the passphrase
`errors.As` identifies the missing passphrase; read it from a secret store, never from source code.
go signer, err := ssh.ParsePrivateKey(keyBytes) var missing *ssh.PassphraseMissingError if errors.As(err, &missing) { passphrase := []byte(os.Getenv("SSH_KEY_PASSPHRASE")) signer, err = ssh.ParsePrivateKeyWithPassphrase(keyBytes, passphrase) } if err != nil { return err } - 2.
Sign through the SSH agent
With `golang.org/x/crypto/ssh/agent`, the private key never enters your process and the passphrase is handled by the agent.
go import "golang.org/x/crypto/ssh/agent" conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { return err } agentClient := agent.NewClient(conn) auth := ssh.PublicKeysCallback(agentClient.Signers) // the agent holds the decrypted key