Netflix/zuul · error · TlsFatalAlert

decrypt_error

decrypt_error

Error message

Invalid or expired client PSk identity

What it means

In ZuulPskServer.getExternalPSK, when the external TLS-PSK provider throws PskCreationFailureException with the TLS alert decrypt_error, it is translated into a TlsFatalAlert(decrypt_error, 'Invalid or expired client PSk identity'). This means the client presented a known-format PSK identity but the key material could not be used: the PSK is wrong, corrupted, or has expired, so the TLS 1.3 handshake fails with a decrypt_error alert.

Solutions

  1. Verify the client's PSK key material matches the server's externalTlsPskProvider records
  2. Check PSK expiry/rotation: reissue credentials if the identity's validity window has lapsed
  3. Ensure clocks are synchronized if expiry is time-based
  4. Confirm no TLS version/cipher-suite mismatch is corrupting key derivation between client and server
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at zuul-core/src/main/java/com/netflix/zuul/netty/server/psk/ZuulPskServer.java:172 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Netflix/zuul@14bf53c52d (2026-09-07). Data as JSON: /api/errors/24371ddc501c639a. Report an issue: GitHub.

Appendix: source

Thrown at zuul-core/src/main/java/com/netflix/zuul/netty/server/psk/ZuulPskServer.java:172

    @Override
    @SneakyThrows
    public TlsPSKExternal getExternalPSK(Vector clientPskIdentities) {
        byte[] clientPskIdentity = ((PskIdentity) clientPskIdentities.get(0)).getIdentity();
        byte[] psk;
        try {
            this.ctx
                    .channel()
                    .attr(TlsPskHandler.CLIENT_PSK_IDENTITY_ATTRIBUTE_KEY)
                    .set(new ClientPSKIdentityInfo(List.copyOf(Bytes.asList(clientPskIdentity))));
            psk = externalTlsPskProvider.provide(
                    clientPskIdentity,
                    this.context.getSecurityParametersHandshake().getClientRandom());
        } catch (PskCreationFailureException e) {
            throw switch (e.getTlsAlertMessage()) {
                case unknown_psk_identity ->
                    new TlsFatalAlert(AlertDescription.unknown_psk_identity, "Unknown or null client PSk identity");
                case decrypt_error ->
                    new TlsFatalAlert(AlertDescription.decrypt_error, "Invalid or expired client PSk identity");
            };
        }
        TlsSecret pskTlsSecret = getCrypto().createSecret(psk);
        int prfAlgorithm = getPRFAlgorithm13(getSelectedCipherSuite());
        return new BasicTlsPSKExternal(clientPskIdentity, pskTlsSecret, prfAlgorithm);
    }

    @Override
    public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) {
        super.notifyAlertRaised(alertLevel, alertDescription, message, cause);
        Consumer<String> loggerFunc = (alertLevel == AlertLevel.fatal) ? LOGGER::error : LOGGER::debug;
        loggerFunc.accept("TLS/PSK server raised alert: " + AlertLevel.getText(alertLevel) + ", "
                + AlertDescription.getText(alertDescription));
        if (message != null) {
            loggerFunc.accept("> " + message);
        }
        if (cause != null) {
            LOGGER.error("TLS/PSK alert stacktrace", cause);

View on GitHub (pinned to 14bf53c52d)