{"record":{"id":"9ba247415c7c4b73","repo":"SonarSource/sonarqube","slug":"failed-to-decode-github-application-private-key","errorCode":null,"errorMessage":"Failed to decode Github Application private key","messagePattern":"Failed to decode Github Application private key","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/security/GithubAppSecurityImpl.java","lineNumber":77,"sourceCode":"    LocalDateTime expiresAt = now.plus(AppToken.EXPIRATION_PERIOD_IN_MINUTES, ChronoUnit.MINUTES);\n    ZoneOffset offset = clock.getZone().getRules().getOffset(now);\n    Date nowDate = Date.from(now.toInstant(offset));\n    Date expiresAtDate = Date.from(expiresAt.toInstant(offset));\n    JWTCreator.Builder builder = JWT.create()\n      .withIssuer(String.valueOf(appId))\n      .withIssuedAt(nowDate)\n      .withExpiresAt(expiresAtDate);\n    return new AppToken(builder.sign(algorithm));\n  }\n\n  private static Algorithm readApplicationPrivateKey(long appId, String encodedPrivateKey) {\n    byte[] decodedPrivateKey = encodedPrivateKey.getBytes(UTF_8);\n    try (PemReader pemReader = new PemReader(new InputStreamReader(new ByteArrayInputStream(decodedPrivateKey)))) {\n      Security.addProvider(new BouncyCastleProvider());\n\n      PemObject pemObject = pemReader.readPemObject();\n      if (pemObject == null) {\n        throw new IllegalArgumentException(\"Failed to decode Github Application private key\");\n      }\n\n      PKCS8EncodedKeySpec keySpec1 = new PKCS8EncodedKeySpec(pemObject.getContent());\n      KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n      PrivateKey privateKey = keyFactory.generatePrivate(keySpec1);\n      return Algorithm.RSA256(new RSAKeyProvider() {\n        @Override\n        public RSAPublicKey getPublicKeyById(String keyId) {\n          throw new UnsupportedOperationException(\"getPublicKeyById not implemented\");\n        }\n\n        @Override\n        public RSAPrivateKey getPrivateKey() {\n          return (RSAPrivateKey) privateKey;\n        }\n\n        @Override\n        public String getPrivateKeyId() {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/github/security/GithubAppSecurityImpl.java#L59-L95","documentation":"Thrown by GithubAppSecurityImpl.readApplicationPrivateKey when the BouncyCastle PemReader parses the provided private key string but no PEM object can be read (parse returns null). The key text is not a valid PEM-encoded block.","triggerScenarios":"readApplicationPrivateKey (via algorithm) receives a key whose bytes contain no recognizable '-----BEGIN ...-----' PEM structure, so pemReader.readPemObject() returns null.","commonSituations":"Key pasted without the BEGIN/END headers; key stored as raw base64 body only; placeholder or wrong value configured; key mangled by shell escaping or JSON escaping.","solutions":["Paste the complete .pem file contents including '-----BEGIN PRIVATE KEY-----' and '-----END PRIVATE KEY-----' lines","Download the private key again from the GitHub App settings page and reconfigure","Ensure the key was not truncated or re-encoded (e.g. double base64) when stored in the settings"],"exampleFix":"// before: privateKey = \"MIIEvQIBADANBg...\" (raw base64, no PEM headers)\n// after: privateKey = \"-----BEGIN PRIVATE KEY-----\\nMIIEvQ...\\n-----END PRIVATE KEY-----\";","handlingStrategy":"validation","validationCode":"function isValidPem(key) {\n  return typeof key === 'string' && /-----BEGIN (RSA )?PRIVATE KEY-----[\\s\\S]+-----END (RSA )?PRIVATE KEY-----/.test(key.trim());\n}","typeGuard":null,"tryCatchPattern":"try { configureGithubApp(appId, privateKey); } catch (IllegalArgumentException e) { log(\"Private key is not valid PEM: \" + e.getMessage()); }","preventionTips":["Paste the entire .pem file including BEGIN/END header and footer lines","Store the key in a settings field that preserves newlines (no shell mangling)","Validate the PEM structure client-side before submitting settings"],"tags":["github","pem","private-key","configuration"],"backgroundTag":"invalid-argument-format","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}