elastic/elasticsearch · critical · IllegalStateException

signature verification for [{}] failed

Error message

signature verification for [{}] failed

What it means

IllegalStateException (unchecked) thrown after `signature.verify()` returns false — meaning the computed hash of the downloaded plugin ZIP bytes did not validate against the detached PGP signature using the public key. The key ID matched (passed the earlier guard) but the content does not verify, indicating corruption or tampering of either the ZIP or the `.asc`. No exit code; runtime exception.

Source

Thrown at distribution/tools/plugin-cli/bc/src/main/java/org/elasticsearch/plugins/cli/bc/PgpSignatureVerifier.java:69

            InputStream fin = pluginZipInputStream;
            InputStream sin = ascInputStream;
            InputStream ain = new ArmoredInputStream(publicKeyInputStream) // input stream to the public key in ASCII-Armor format (RFC4880)
        ) {
            final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin));
            final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0);

            // validate the signature has key ID matching our public key ID
            final String keyId = Long.toHexString(signature.getKeyID()).toUpperCase(Locale.ROOT);
            if (publicKeyId.equals(keyId) == false) {
                throw new IllegalStateException("key id [" + keyId + "] does not match expected key id [" + publicKeyId + "]");
            }

            // compute the signature of the downloaded plugin zip
            computeSignatureForDownloadedPlugin(fin, ain, signature);

            // finally we verify the signature of the downloaded plugin zip matches the expected signature
            if (signature.verify() == false) {
                throw new IllegalStateException("signature verification for [" + urlString + "] failed");
            }
        } catch (PGPException e) {
            throw new IOException("PGP exception during signature verification for [" + urlString + "]", e);
        }
    }

    private static void computeSignatureForDownloadedPlugin(InputStream fin, InputStream ain, PGPSignature signature) throws PGPException,
        IOException {
        final PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(ain, new JcaKeyFingerprintCalculator());
        final PGPPublicKey key = collection.getPublicKey(signature.getKeyID());
        signature.init(new JcaPGPContentVerifierBuilderProvider(), key);
        final byte[] buffer = new byte[1024];
        int read;
        while ((read = fin.read(buffer)) != -1) {
            signature.update(buffer, 0, read);
        }
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Re-download both the plugin ZIP and its `.asc` from the official source and retry.
  2. Clear any local/corporate-proxy cache that may have served a stale copy.
  3. Verify checksums of both files against the published release manifest.
  4. If persistently failing on a specific version, check Elastic's advisories for a known bad artifact.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    PgpSignatureVerifier.verifySignature(publicKeyId, url, zip, asc, pubKey);
} catch (IllegalStateException e) {
    // signature verify=false: re-download both ZIP and .asc, then retry once; never proceed unsigned
    redownloadAndRetry();
}

Prevention

When it happens

Trigger: Truncated or corrupted plugin ZIP (partial download); a `.asc` that belongs to a different build of the same plugin; CDN/cache serving a stale ZIP with the current signature; deliberate tampering that changes bytes but keeps the old signature.

Common situations: Flaky downloads leaving a truncated file; mirror desync; version skew between cached ZIP and freshly fetched signature.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/ee391af162c6dad8. Report an issue: GitHub.