spring-projects/spring-boot · error · IllegalStateException

Missing private key or unrecognized format

Error message

Missing private key or unrecognized format

What it means

All four PEM_PARSERS returned null because none of their header regexes (PKCS1 RSA, SEC1 EC, PKCS8, encrypted PKCS8) matched the input text. parse then falls through to line 220 and throws IllegalStateException. The file is present and non-null but contains no recognizable PEM private key block.

Solutions

  1. Confirm the file actually contains a private key: look for a `-----BEGIN ... PRIVATE KEY-----` line.
  2. Convert a DER key to PEM: `openssl pkey -in der-key.der -out key.pem`.
  3. Convert an OpenSSH key to PEM: `ssh-keygen -p -m PEM -f id_ed25519`, or `openssl pkey -in id_ed25519 -out key.pem`.
  4. Convert a PKCS8 unencrypted key: `openssl pkcs8 -topk8 -nocrypt -in key.pem -out key-pkcs8.pem`.

Example fix

// before: pointing keyPath at an OpenSSH-format key
Path keyPath = Path.of("id_ed25519"); // -----BEGIN OPENSSH PRIVATE KEY-----
// after: convert first, then point at standard PEM
//   $ ssh-keygen -p -m PEM -f id_ed25519
Path keyPath = Path.of("id_ed25519"); // now -----BEGIN PRIVATE KEY-----
Defensive patterns

Strategy: validation

Validate before calling

// Reject non-PEM or unsupported private key files before parsing
String text = Files.readString(keyPath);
boolean hasPemHeader = text.contains("-----BEGIN RSA PRIVATE KEY-----")
        || text.contains("-----BEGIN EC PRIVATE KEY-----")
        || text.contains("-----BEGIN PRIVATE KEY-----")
        || text.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----");
if (!hasPemHeader) {
    throw new IllegalArgumentException(
        keyPath + " is not a recognized PEM private key. Convert with: "
        + "openssl pkcs8 -topk8 -nocrypt -in <key> -out <key>.pem");
}

Try / catch

try {
    PemPrivateKeyParser.parse(text, password);
} catch (IllegalStateException ex) {
    if (ex.getMessage().equals("Missing private key or unrecognized format")) {
        // hint: convert OpenSSH/DER keys to standard PEM PKCS8
    }
    throw ex;
}

Prevention

When it happens

Trigger: parse(text, password) is called with a non-null text whose contents contain no BEGIN ... PRIVATE KEY header that any parser recognizes: a binary DER key, a certificate, a public key, an OpenSSH-format key (BEGIN OPENSSH PRIVATE KEY), or an empty/garbage file.

Common situations: Pointing keyPath at a .crt/.pub file; a binary .der private key; an OpenSSH-format Ed25519/RSA key; an empty file; a PKCS7/PFX bundle.

Related errors


AI-assisted analysis of spring-projects/spring-boot@270dfe353f (2026-08-11). Data as JSON: /api/errors/d7063da8c3963baf. Report an issue: GitHub.

Appendix: source

Thrown at buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/PemPrivateKeyParser.java:220

	 * @param password the password used to decrypt an encrypted private key
	 * @return the parsed private key
	 */
	static @Nullable PrivateKey parse(@Nullable String text, @Nullable String password) {
		if (text == null) {
			return null;
		}
		try {
			for (PemParser pemParser : PEM_PARSERS) {
				PrivateKey privateKey = pemParser.parse(text, password);
				if (privateKey != null) {
					return privateKey;
				}
			}
		}
		catch (Exception ex) {
			throw new IllegalStateException("Error loading private key file: " + ex.getMessage(), ex);
		}
		throw new IllegalStateException("Missing private key or unrecognized format");
	}

	/**
	 * Parser for a specific PEM format.
	 */
	private static class PemParser {

		private final Pattern pattern;

		private final BiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory;

		private final String[] algorithms;

		PemParser(String header, String footer,
				BiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory, String... algorithms) {
			this.pattern = Pattern.compile(header + BASE64_TEXT + footer, Pattern.CASE_INSENSITIVE);
			this.keySpecFactory = keySpecFactory;
			this.algorithms = algorithms;

View on GitHub (pinned to 270dfe353f)