{"record":{"id":"93919342e63b052d","repo":"gradle/gradle","slug":"could-not-read-signatures-from-s-s-s","errorCode":null,"errorMessage":"Could not read signatures from %s: %s: %s","messagePattern":"Could not read signatures from (.+?): (.+?): (.+?)","errorType":"exception","errorClass":"InvalidSignatureFileException","httpStatus":null,"severity":"error","filePath":"platforms/software/security/src/main/java/org/gradle/security/internal/SecuritySupport.java","lineNumber":88,"sourceCode":"        } catch (IOException e) {\n            throw UncheckedException.throwAsUncheckedException(e);\n        }\n        return signature.verify();\n    }\n\n    private static PGPContentVerifierBuilderProvider createContentVerifier() {\n        return new BcPGPContentVerifierBuilderProvider();\n    }\n\n    @Nullable\n    public static PGPSignatureList readSignatures(File file) {\n        try (\n            InputStream stream = new BufferedInputStream(Files.newInputStream(file.toPath()));\n            InputStream decoderStream = PGPUtil.getDecoderStream(stream)\n        ) {\n            return readSignatureList(decoderStream, file.toString());\n        } catch (IOException | PGPException e) {\n            throw new InvalidSignatureFileException(file, e);\n        }\n    }\n\n    @Nullable\n    private static PGPSignatureList readSignatureList(InputStream decoderStream, String locationHint) throws IOException, PGPException {\n        PGPObjectFactory objectFactory = new PGPObjectFactory(decoderStream, new BcKeyFingerprintCalculator());\n        Object nextObject = objectFactory.nextObject();\n        if (nextObject instanceof PGPSignatureList) {\n            return (PGPSignatureList) nextObject;\n        } else if (nextObject instanceof PGPCompressedData) {\n            return readSignatureList(((PGPCompressedData) nextObject).getDataStream(), locationHint);\n        } else {\n            LOGGER.warn(\"Expected a signature list in {}, but got {}. Skipping this signature.\", locationHint, nextObject == null ? \"invalid file\" : nextObject.getClass());\n            return null;\n        }\n    }\n\n    public static String toLongIdHexString(long key) {","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/security/src/main/java/org/gradle/security/internal/SecuritySupport.java#L70-L106","documentation":"SecuritySupport.readSignatures(File) opens a signature file, wraps it in PGPUtil.getDecoderStream (auto-detects ASCII armor and compression), and parses the first PGPSignatureList object. Any IOException or PGPException is rethrown as InvalidSignatureFileException with the message 'Could not read signatures from <file>: <cause class>: <cause message>'. It means the file could not be read as an OpenPGP signature stream.","triggerScenarios":"Passing the artifact binary instead of its .asc detached signature; a truncated or zero-byte .asc from an interrupted download; a file with broken armor headers (missing BEGIN PGP SIGNATURE); or an I/O error (permissions, disk) while reading.","commonSituations":"Dependency verification failing on corrupt cached files under ~/.gradle/caches/modules-2; artifacts republished to a mirror without signatures; CI caches containing partial downloads; disk-full leaving half-written .asc files.","solutions":["Confirm the file is actually a signature: run gpg --list-packets artifact.asc","Delete the cached module directory and re-resolve: rm -rf ~/.gradle/caches/modules-2/files-2.1/<group>/<module>","Re-download the artifact and its signature from a repository that publishes both","If the module genuinely has no signature, adjust verification metadata (trusted artifacts entry) rather than pointing at a non-signature file"],"exampleFix":"# before: build fails with InvalidSignatureFileException on a cached artifact\n\n# inspect the offending file\ngpg --list-packets ~/.gradle/caches/modules-2/files-2.1/my.group/mymodule/*/artifact.jar.asc\n\n# clear the corrupt cached module and rebuild\nrm -rf ~/.gradle/caches/modules-2/files-2.1/my.group/mymodule\n./gradlew build --refresh-dependencies","handlingStrategy":"try-catch","validationCode":"File asc = new File(artifactPath + \".asc\");\nif (!asc.exists() || asc.length() == 0) {\n    throw new IllegalStateException(\"Signature missing or empty: \" + asc);\n}","typeGuard":null,"tryCatchPattern":"try {\n    PGPSignatureList signatures = SecuritySupport.readSignatures(sigFile);\n} catch (InvalidSignatureFileException e) {\n    // e carries file + root cause; decide: re-download, or record as unverified\n    log.warn(\"Unreadable signature {}: {}\", sigFile, e.getCause().getMessage());\n    return VerificationResult.unverified(sigFile, e);\n}","preventionTips":["Check the .asc exists and is non-empty before enabling verification for a module","Treat partial downloads as poison: verify checksums at download time so caches never hold truncated files","Keep a scripted cache-clean step (delete the module dir under modules-2/files-2.1) for signature corruption"],"tags":["gradle","pgp","signatures","dependency-verification","io"],"backgroundTag":"pgp-signature-file-invalid","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}