elastic/elasticsearch · error · IllegalStateException

String [{}] is not hexadecimal

Error message

String [{}] is not hexadecimal

What it means

Thrown by hexStringToByteArray when at least one character in an even-length input string is not a valid hexadecimal digit (Character.digit returns -1). This is an IllegalStateException (unchecked) and currently surfaces from the IV-parsing path inside getCipherFromParameters, where it is wrapped into the 'DEK-Info IV is invalid' IOException. The message echoes the offending string verbatim.

Source

Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java:580

            }
            md5.update(tempDigest, 0, 16); // use previous round digest as IV
        }
        Arrays.fill(passwordBytes, (byte) 0);
        return key;
    }

    /**
     * Converts a hexadecimal string to a byte array
     */
    private static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        if (len % 2 == 0) {
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                final int k = Character.digit(hexString.charAt(i), 16);
                final int l = Character.digit(hexString.charAt(i + 1), 16);
                if (k == -1 || l == -1) {
                    throw new IllegalStateException("String [" + hexString + "] is not hexadecimal");
                }
                data[i / 2] = (byte) ((k << 4) + l);
            }
            return data;
        } else {
            throw new IllegalStateException(
                "Hexadecimal string [" + hexString + "] has odd length and cannot be converted to a byte array"
            );
        }
    }

    /**
     * Parses a DER encoded EC key to an {@link ECPrivateKeySpec} using a minimal {@link DerParser}
     *
     * @param keyBytes the private key raw bytes
     * @return {@link ECPrivateKeySpec}
     * @throws IOException if the DER encoded key can't be parsed
     */

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the hex string and replace any non-hex characters (only 0-9 and A-F/a-f are valid).
  2. Regenerate the encrypted key so the IV is fresh and valid: 'openssl rsa -aes256 -in plain.key -out enc.key'.
  3. Add a pre-validation step in your code that rejects non-hex strings before calling the API (see defense section).
Defensive patterns

Strategy: validation

Validate before calling

// Validate a hex string with explicit error reporting
static byte[] requireHex(String s) {
    if (s.length() % 2 != 0) throw new IllegalArgumentException("odd length");
    for (int i = 0; i < s.length(); i++) {
        if (Character.digit(s.charAt(i), 16) == -1) {
            throw new IllegalArgumentException("non-hex char at index " + i + " in " + s);
        }
    }
    return java.util.HexFormat.of().parseHex(s);
}

Try / catch

try { PemUtils.readPrivateKey(path, passwordSupplier); }
catch (RuntimeException e) { if (e.getMessage().contains("is not hexadecimal")) { /* regenerate key */ } else throw e; }

Prevention

When it happens

Trigger: Passing a DEK-Info IV (or any hex string) that contains non-hex characters such as 'O' instead of '0', 'l' instead of '1', whitespace, or punctuation; a corrupted or hand-edited IV.

Common situations: Manual editing of PEM headers; OCR or copy-paste that substituted look-alike characters; a templating system that mangled the hex; locale-specific digit substitutions.

Related errors


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