{"record":{"id":"7bc644ff309c3b6f","repo":"grpc/grpc-java","slug":"unable-to-decode-private-key","errorCode":null,"errorMessage":"Unable to decode private key","messagePattern":"Unable to decode private key","errorType":"validation","errorClass":"GeneralSecurityException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java","lineNumber":720,"sourceCode":"      throws GeneralSecurityException {\n    InputStream certChainStream = new ByteArrayInputStream(certChain);\n    InputStream privateKeyStream = new ByteArrayInputStream(privateKey);\n    try {\n      return createKeyManager(certChainStream, privateKeyStream);\n    } finally {\n      GrpcUtil.closeQuietly(certChainStream);\n      GrpcUtil.closeQuietly(privateKeyStream);\n    }\n  }\n\n  static KeyManager[] createKeyManager(InputStream certChain, InputStream privateKey)\n      throws GeneralSecurityException {\n    X509Certificate[] chain = CertificateUtils.getX509Certificates(certChain);\n    PrivateKey key;\n    try {\n      key = CertificateUtils.getPrivateKey(privateKey);\n    } catch (IOException uee) {\n      throw new GeneralSecurityException(\"Unable to decode private key\", uee);\n    }\n    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n    try {\n      ks.load(null, null);\n    } catch (IOException ex) {\n      // Shouldn't really happen, as we're not loading any data.\n      throw new GeneralSecurityException(ex);\n    }\n    ks.setKeyEntry(\"key\", key, new char[0], chain);\n\n    KeyManagerFactory keyManagerFactory =\n        KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n    keyManagerFactory.init(ks, new char[0]);\n    return keyManagerFactory.getKeyManagers();\n  }\n\n  static TrustManager[] createTrustManager(byte[] rootCerts) throws GeneralSecurityException {\n    InputStream rootCertsStream = new ByteArrayInputStream(rootCerts);","sourceCodeStart":702,"sourceCodeEnd":738,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java#L702-L738","documentation":"createKeyManager wraps IOException from CertificateUtils.getPrivateKey in a GeneralSecurityException 'Unable to decode private key'. The supplied private key file could not be parsed into a PrivateKey (bad format, wrong PEM type, encrypted key without password support).","triggerScenarios":"Passing a private key to TlsChannelCredentials keyManager / createKeyManager that is DER vs PEM mismatched, encrypted (PKCS#8 with passphrase), corrupted, or actually a certificate rather than a key.","commonSituations":"Using PKCS#1 'BEGIN RSA PRIVATE KEY' where the parser expects PKCS#8, encrypted keys, copy-paste truncating the PEM, swapping cert and key arguments.","solutions":["Convert the key to unencrypted PKCS#8: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key8.pem","Verify the file is the private key, not the certificate chain, and is complete PEM","Regenerate or re-export the key in PEM format from the source keystore","If encrypted, decrypt it first or use a credentials API that accepts a password"],"exampleFix":"// before\nTlsChannelCredentials.newBuilder().keyManager(certChain, privateKeyPkcs1Encrypted)... // decode fails\n// after\n// convert: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem\nTlsChannelCredentials.newBuilder().keyManager(certChain, keyPkcs8)...","handlingStrategy":"validation","validationCode":"if (!pemContains(privateKeyPem, \"PRIVATE KEY\")) throw new IllegalArgumentException(\"file is not a PEM private key\");","typeGuard":null,"tryCatchPattern":"try { creds = TlsChannelCredentials.newBuilder().keyManager(cert, key).build(); } catch (GeneralSecurityException e) { if (e.getMessage().contains(\"Unable to decode private key\")) { convertKeyToPkcs8(); creds = rebuild(); } else { throw e; } }","preventionTips":["Always ship unencrypted PKCS#8 PEM keys","Check PEM headers: 'BEGIN PRIVATE KEY' vs 'BEGIN RSA PRIVATE KEY'","Open and inspect the key file before passing its path"],"tags":["grpc","okhttp","tls","private-key","pem"],"backgroundTag":"invalid-argument-format","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}