apache/pulsar · error · IOException
Failed to decode public key
Error message
Failed to decode public key
What it means
AuthTokenUtils.decodePublicKey wraps any failure while parsing an X.509-encoded public key (for RSA or EC signature algorithms) into an IOException. KeyFactory.generatePublic rejects the bytes if they are not a valid DER/X.509 SubjectPublicKeyInfo structure or do not match the expected key algorithm.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/utils/AuthTokenUtils.java:75
public static PrivateKey decodePrivateKey(byte[] key, SignatureAlgorithm algType) throws IOException {
try {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));
return kf.generatePrivate(spec);
} catch (Exception e) {
throw new IOException("Failed to decode private key", e);
}
}
public static PublicKey decodePublicKey(byte[] key, SignatureAlgorithm algType) throws IOException {
try {
X509EncodedKeySpec spec = new X509EncodedKeySpec(key);
KeyFactory kf = KeyFactory.getInstance(keyTypeForSignatureAlgorithm(algType));
return kf.generatePublic(spec);
} catch (Exception e) {
throw new IOException("Failed to decode public key", e);
}
}
private static String keyTypeForSignatureAlgorithm(SignatureAlgorithm alg) {
if (alg.getFamilyName().equals("RSA")) {
return "RSA";
} else if (alg.getFamilyName().equals("ECDSA")) {
return "EC";
} else {
String msg = "The " + alg.name() + " algorithm does not support Key Pairs.";
throw new IllegalArgumentException(msg);
}
}
public static String encodeKeyBase64(Key key) {
return Encoders.BASE64.encode(key.getEncoded());
}
View on GitHub (pinned to 820761864e)
Solutions
- Verify the input is a public key in X.509/SubjectPublicKeyInfo (SPKI) DER format; regenerate with `openssl rsa -pubout` or `openssl ec -pubout` and base64-encode the DER bytes.
- Strip PEM armor and whitespace before calling decodePublicKey — it expects raw DER bytes, not the '-----BEGIN PUBLIC KEY-----' text.
- Ensure the SignatureAlgorithm matches the key family (RSA key with RSA alg, EC key with ECDSA alg).
- Confirm the base64 string decodes cleanly (Decoders.BASE64.decode in a test) and was not truncated by copy/paste or line wrapping.
Example fix
// before
byte[] key = Files.readAllBytes(Path.of("public.key")); // file contains PEM text
PublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256);
// after
String pem = Files.readString(Path.of("public.key"));
String b64 = pem.replaceAll("-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\\s", "");
byte[] key = Base64.getDecoder().decode(b64);
PublicKey pk = AuthTokenUtils.decodePublicKey(key, SignatureAlgorithm.RS256); Defensive patterns
Strategy: validation
Validate before calling
byte[] der = Base64.getDecoder().decode(cleanB64);
if (der.length == 0 || der[0] != 0x30) throw new IllegalArgumentException("not DER/SPKI public key");
new X509EncodedKeySpec(der); // parses or throws before calling the API Type guard
boolean isSpkiPublicKey(byte[] b) { return b != null && b.length > 0 && b[0] == 0x30; } Try / catch
try { PublicKey pk = AuthTokenUtils.decodePublicKey(bytes, alg); } catch (IOException e) { log.error("bad public key material", e); throw new ConfigurationException("check tokenPublicKey: must be base64 X.509 SPKI"); } Prevention
- Always generate public keys with `openssl -pubout` and base64-encode the DER form
- Strip PEM headers/footers and whitespace before decoding
- Never pass private-key bytes to decodePublicKey
- Match the key family to the SignatureAlgorithm
When it happens
Trigger: Calling decodePublicKey(byte[], SignatureAlgorithm) with bytes that are not a valid X509EncodedKeySpec: corrupted key file contents, a PEM body with surrounding junk, a private key passed where a public key is expected, or truncated base64 input.
Common situations: Passing the contents of a PKCS#8 private key file instead of the public key; pasting a raw hex key instead of base64 DER; hand-editing a key file and corrupting the encoding; using a key generated for a different algorithm than the configured algType.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- The ${alg.name()} algorithm does not support Key Pairs.
- Authentication has not completed
- Not supported
- Illegal base64 character or Key file ${keyConfUrl} doesn't e
- Secret/Public Key file ${keyConfUrl} doesn't exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/6072ddedc881c699.
Report an issue: GitHub.