{"record":{"id":"4c6d0129cc25f894","repo":"gradle/gradle","slug":"could-not-read-pgp-secret-key","errorCode":null,"errorMessage":"Could not read PGP secret key","messagePattern":"Could not read PGP secret key","errorType":"exception","errorClass":"InvalidUserDataException","httpStatus":null,"severity":"error","filePath":"platforms/software/signing/src/main/java/org/gradle/plugins/signing/signatory/internal/pgp/PgpSignatoryUtil.java","lineNumber":181,"sourceCode":"     *\n     * @param keyId the id of the key, can be null to return the only master secret key\n     * @param keyData the ASCII-armored representation of the key\n     * @return the parsed secret key\n     */\n    public static PGPSecretKey parseSecretKey(@Nullable String keyId, String keyData) {\n        try (InputStream in = PGPUtil.getDecoderStream(new ByteArrayInputStream(keyData.getBytes(UTF_8)))) {\n            if (keyId == null) {\n                return new JcaPGPSecretKeyRing(in).getSecretKey();\n            } else {\n                PgpKeyId expectedKeyId = new PgpKeyId(keyId);\n                PGPSecretKey key = findSecretKey(new JcaPGPSecretKeyRingCollection(in), expectedKeyId);\n                if (key != null) {\n                    return key;\n                }\n                throw new InvalidUserDataException(String.format(\"Cannot find key with id '%s' in key data\",  keyId));\n            }\n        } catch (IOException | PGPException e) {\n            throw new InvalidUserDataException(\"Could not read PGP secret key\", e);\n        }\n    }\n}\n","sourceCodeStart":163,"sourceCodeEnd":185,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/signing/src/main/java/org/gradle/plugins/signing/signatory/internal/pgp/PgpSignatoryUtil.java#L163-L185","documentation":"parseSecretKey wraps its parsing stream in try-with-resources; any IOException or PGPException while reading the in-memory key data is rethrown as InvalidUserDataException 'Could not read PGP secret key' with the original as cause. The bytes could not be decoded as an OpenPGP secret key at all.","triggerScenarios":"Secret key string with a mangled armored block (missing BEGIN/END lines, folded newlines in CI env vars, escaped \\n instead of real newlines, base64 corruption, HTML-escaped output pasted from a web UI).","commonSituations":"CI secret variables that collapse multiline values; copying an armored key from a chat/wiki that wraps lines; double-encoding (base64 of base64); truncation at a size limit of the secrets manager.","solutions":["Ensure the secret contains the full armored block verbatim, including -----BEGIN PGP PRIVATE KEY BLOCK----- and -----END PGP PRIVATE KEY BLOCK----- lines","Validate locally before injecting: echo \"$KEY\" | gpg --list-packets must succeed","Use proper multiline secret storage (GitHub Actions secrets, Vault kv with multiline support) rather than joining lines manually","Check the cause chain: the wrapped PGPException/IOException usually names the exact decode failure"],"exampleFix":"# before: CI collapses newlines -> \"Could not read PGP secret key\"\n\n# after: store and pass the full armored block, then self-check before the build\n- name: Verify signing key\n  run: printf '%s' \"$ORG_GRADLE_PROJECT_signingKey\" | gpg --list-packets >/dev/null\n- run: ./gradlew publish","handlingStrategy":"try-catch","validationCode":"// fail early in CI if the secret is mangled\n- run: printf '%s' \"$SIGNING_KEY\" | gpg --list-packets > /dev/null","typeGuard":null,"tryCatchPattern":"try {\n    def key = PgpSignatoryUtil.parseSecretKey(keyId, secretKeyString)\n} catch (InvalidUserDataException e) {\n    def cause = e.cause?.message ?: ''\n    throw new GradleException(\"Injected PGP key is unreadable (${cause}); check multiline escaping of the secret\", e)\n}","preventionTips":["Store armored keys as true multiline secrets; never join lines manually","Self-check every signing secret with gpg --list-packets before the build step","Always inspect the cause (PGPException/IOException) to pinpoint armor vs base64 corruption"],"tags":["gradle","signing","pgp","secrets","ci","file-format"],"backgroundTag":"pgp-keyring-parse-error","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}