OpenSSH prints "Load key: invalid format" when it cannot parse a private key file. This is usually caused by a mangled key (lost newlines from copy-paste or CI variables), or by passing a .pub file instead of the private key.
The "Load key: invalid format" message means OpenSSH found and opened the private key file you pointed it at, but could not decode the key material inside it. The file is present and readable, yet its contents do not match any private key structure OpenSSH understands. This is a parsing failure, not an authentication or permissions failure. In the overwhelming majority of cases the key bytes have been damaged in transit: the header/footer lines were dropped, internal newlines were collapsed into spaces, CRLF line endings were introduced on Windows, or the base64 body was truncated. This happens constantly when keys are pasted into CI/CD secret fields, environment variables, web forms, or chat tools that reflow whitespace. A close second is simply pointing SSH at the wrong file — most often the public key (id_ed25519.pub) instead of the private key. A genuine key-format mismatch is far less common. OpenSSH itself reads both its native format (-----BEGIN OPENSSH PRIVATE KEY-----) and the legacy PEM/PKCS#1 RSA format (-----BEGIN RSA PRIVATE KEY-----) without complaint. Format mismatches mainly bite older third-party tooling (legacy PuTTY, some old language SSH libraries, certain cloud key importers) that predate the OpenSSH format introduced in OpenSSH 7.8 (2018).
Look at the first and last lines of the file SSH is rejecting:
head -1 ~/.ssh/id_ed25519
tail -1 ~/.ssh/id_ed25519A valid private key starts and ends with matching markers, for example:
- -----BEGIN OPENSSH PRIVATE KEY----- … -----END OPENSSH PRIVATE KEY----- (modern OpenSSH default for any key type)
- -----BEGIN RSA PRIVATE KEY----- … -----END RSA PRIVATE KEY----- (legacy PEM/PKCS#1 RSA)
- -----BEGIN PRIVATE KEY----- … -----END PRIVATE KEY----- (PKCS#8, any type)
If the first line is ssh-rsa AAAA... or ssh-ed25519 AAAA..., or the filename ends in .pub, you are using the public key by mistake. Point SSH at the private key (the file without the .pub extension) instead.
Most 'invalid format' failures are damaged whitespace. Confirm the file has proper Unix line breaks and no hidden characters:
# Show non-printing characters. Lines should end in $ with no ^M before them.
cat -A ~/.ssh/id_ed25519 | head- A trailing ^M$ on each line means Windows CRLF endings. Convert them:
sed -i 's/\r$//' ~/.ssh/id_ed25519- If the whole key sits on one line (header, body, and footer run together), the newlines were stripped during copy/paste and the key must be re-created from a clean source. A PEM/OpenSSH key requires real line breaks; re-paste it from the original file using a method that preserves newlines, or regenerate it (Step 5).
Always copy keys with tools that preserve formatting (scp, ssh-copy-id, file upload) rather than pasting into chat or web fields.
Pipelines are the number-one source of this error because secret stores and shell expansion frequently collapse newlines.
Preferred approach — write the secret to a file with permissions locked down before use:
# The secret must contain real newlines exactly as in the original key file.
install -m 600 /dev/null ~/.ssh/ci_key # create file as 0600 up front
printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/ci_key # printf preserves embedded newlines
chmod 600 ~/.ssh/ci_key # ensure 0600 (never world-readable)
ssh -i ~/.ssh/ci_key user@host> Private key files must be mode 0600 (owner read/write only). OpenSSH will refuse a key that is group- or world-readable.
If your secret store strips newlines, base64-encode the key when you store it, then decode it at runtime so no newline handling is required in the variable:
# One-time, locally: encode the key for storage in the secret.
base64 -w0 ~/.ssh/id_ed25519 # paste this single-line output into the CI secret
# In the pipeline: decode it back to the real key, 0600 from the start.
install -m 600 /dev/null ~/.ssh/ci_key
printf '%s' "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/ci_key
chmod 600 ~/.ssh/ci_keyThis is needed only when a specific older tool cannot read the OpenSSH format — modern OpenSSH itself reads both. The legacy PEM (PKCS#1) format applies to RSA keys:
# Work on a copy so you never risk your only key.
cp ~/.ssh/id_rsa ~/.ssh/id_rsa_pem
# Convert the copy in place to PEM (PKCS#1). Enter the current passphrase if prompted.
ssh-keygen -p -m PEM -f ~/.ssh/id_rsa_pem
# Verify:
head -1 ~/.ssh/id_rsa_pem # -----BEGIN RSA PRIVATE KEY-----Important: -m PEM produces a legacy PKCS#1/SEC1 key only for RSA (and SEC1 for ECDSA). Ed25519 keys cannot be stored in legacy PEM format — they only exist in the OpenSSH format (or PKCS#8). Do not try ssh-keygen -m PEM on an Ed25519 key; it will not produce a usable PEM key. If an old tool needs a non-OpenSSH Ed25519 key, export it as PKCS#8 instead:
# PKCS#8 export (modern, widely supported; works for Ed25519, ECDSA, RSA)
ssh-keygen -e -m PKCS8 -f ~/.ssh/id_ed25519 # writes the PUBLIC key in PKCS#8For private-key conversion to PKCS#8 use OpenSSL on a copy if the tool truly requires it. In most cases the better fix is to upgrade the consuming tool to a version that understands the OpenSSH format.
If the file is damaged beyond repair, generate a fresh key. Ed25519 is the recommended default — it is fast, compact, and secure:
# Recommended: Ed25519 (stored in OpenSSH format, which all current SSH reads)
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519
# If you specifically need a legacy-PEM RSA key for an old tool:
ssh-keygen -t rsa -b 4096 -m PEM -C "[email protected]" -f ~/.ssh/id_rsaUse a passphrase when prompted unless an automated system genuinely cannot supply one. Then install the new public key on the server (this does not overwrite other authorized keys):
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostIf you replaced an old key, remove its line from ~/.ssh/authorized_keys on each server afterwards.
PuTTY uses its own .ppk format; pointing OpenSSH at a .ppk file (or vice versa) yields 'invalid format'.
To use a PuTTY key with OpenSSH: open PuTTYgen, click Load and select the .ppk, then Conversions → Export OpenSSH key and save it. Use that exported file with ssh -i.
To use an OpenSSH key with PuTTY: load the OpenSSH private key in PuTTYgen and Save private key as .ppk.
Alternatively, Windows now ships OpenSSH and includes ssh-keygen, so you can generate and use keys directly in PowerShell or Git Bash without PuTTY:
ssh-keygen -t ed25519 -f $HOME/.ssh/id_ed25519Once the key parses, verify authentication with verbose output:
ssh -v -i ~/.ssh/id_ed25519 user@host
# Success looks like: 'Offering public key', then 'Server accepts key',
# then 'Authentication succeeded (publickey)'.For Git hosting:
ssh -T [email protected]
# -> Hi <username>! You've successfully authenticated...If you manage several keys, pin the right one in ~/.ssh/config so SSH does not offer the wrong key:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesThe 'invalid format' message should be gone. If it persists, re-check Steps 1–2: the file you are pointing at is almost certainly still the wrong file or still has mangled newlines.
Key formats, accurately
| Header | Key types | Notes |
|--------|-----------|-------|
| -----BEGIN OPENSSH PRIVATE KEY----- | RSA, Ed25519, ECDSA | OpenSSH's own format; default since OpenSSH 7.8 (2018). The only format Ed25519 private keys use. |
| -----BEGIN RSA PRIVATE KEY----- | RSA only | Legacy PEM / PKCS#1. Produced by ssh-keygen -m PEM for RSA, or by older OpenSSH. |
| -----BEGIN EC PRIVATE KEY----- | ECDSA only | SEC1 PEM. Never used for Ed25519 — Ed25519 is not an "EC PRIVATE KEY". |
| -----BEGIN PRIVATE KEY----- | Any | PKCS#8; what OpenSSL and many libraries emit. |
A common myth is that Ed25519 keys can be exported to legacy PEM with -m PEM. They cannot: there is no PKCS#1/SEC1 representation for Ed25519. Ed25519 private keys live in the OpenSSH format; if a tool needs something else, PKCS#8 is the portable option, not "PEM".
Why the OpenSSH format exists
The OpenSSH format adds a bcrypt-based KDF for passphrase-protected keys, giving much stronger resistance to offline brute-forcing than the old PEM encryption. For unencrypted keys the on-disk security is equivalent; the win is only meaningful when a passphrase is set.
Diagnosing in CI without leaking secrets
Never echo a private key to build logs. To check structure safely, count lines and verify the markers without printing the body:
# Does not reveal key material:
head -1 ~/.ssh/ci_key; tail -1 ~/.ssh/ci_key; wc -l < ~/.ssh/ci_keyA well-formed key has multiple lines and matching BEGIN/END markers. A single-line result is the classic stripped-newline failure.
Hygiene
Keep private keys at mode 0600 and their directory at 0700. Never commit private keys to version control, paste them into chat/issue trackers, or store them unencrypted where others can read them. If a key may have been exposed, rotate it: generate a new pair, deploy the new public key, and remove the old one from every authorized_keys.
sign_and_send_pubkey: no mutual signature supported
How to fix "sign_and_send_pubkey: no mutual signature supported" in SSH
sign_and_send_pubkey: signing failed for RSA from agent: agent refused operation
How to fix "sign_and_send_pubkey: signing failed for RSA from agent: agent refused operation" in SSH
Bad owner or permissions on /home/user/.ssh/config
How to fix "Bad owner or permissions on .ssh/config" in SSH
No more authentication methods to try.
How to fix "No more authentication methods to try." in SSH
Error connecting to agent: Connection refused
How to fix "Error connecting to agent: Connection refused" in SSH