nathanmarz/storm · critical · RuntimeException

Blowfish encryption key invalid

Error message

Blowfish encryption key invalid

What it means

BlowfishTupleSerializer decodes the configured encryption key from a hex string with Apache Commons Codec's Hex.decodeHex. If the configured key is not valid hexadecimal (odd length or non-hex characters), decodeHex throws DecoderException and the constructor wraps it in this RuntimeException('Blowfish encryption key invalid', ex).

Solutions

  1. Replace the key with a valid even-length hex string (characters 0-9a-f only), e.g. generate one with 'openssl rand -hex 16'.
  2. Strip quotes, whitespace, and newlines from the value in storm.yaml.
  3. Keep the key at a reasonable length ( Blowfish supports 32–448 bit keys, so 8–56 hex-decoded bytes).
  4. Ensure the same corrected key is deployed to all nodes so workers agree on the key.

Example fix

// storm.yaml before (passphrase, not hex)
topology.tuple.secret.key: "my secret pass phrase"
// after
topology.tuple.secret.key: "3f8a1c9d2b7e4f6a1c9d2b7e4f6a1c9d"
Defensive patterns

Strategy: validation

Validate before calling

String key = (String) stormConf.get("topology.tuple.secret.key");
if (key != null && (!key.matches("[0-9a-fA-F]+") || key.length() % 2 != 0)) {
    throw new IllegalArgumentException("Blowfish secret key must be a valid even-length hex string");
}

Try / catch

try {
    byte[] bytes = Hex.decodeHex(key.toCharArray());
    // proceed with key
} catch (org.apache.commons.codec.DecoderException e) {
    throw new IllegalArgumentException("Configured Blowfish key is not valid hex: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Setting the Blowfish secret-key config value to a non-hex string (e.g. plain text 'mysecretkey', a base64 key, or a key with stray whitespace/quotes) when BlowfishTupleSerializer is constructed with that storm_conf.

Common situations: Pasting a YAML string with accidental quotes or trailing spaces into storm.yaml; using a passphrase instead of a hex-encoded key; copying a key with a trailing newline from a CLI generator; accidentally generating an odd-length hex string by hand.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/9fba1ee120bb08d8. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/security/serialization/BlowfishTupleSerializer.java:60

     * The secret key (if any) for data encryption by blowfish payload serialization factory (BlowfishSerializationFactory). 
     * You should use in via "storm -c topology.tuple.serializer.blowfish.key=YOURKEY -c topology.tuple.serializer=backtype.storm.security.serialization.BlowfishTupleSerializer jar ...".
     */
    public static String SECRET_KEY = "topology.tuple.serializer.blowfish.key";
    private static final Logger LOG = Logger.getLogger(BlowfishTupleSerializer.class);
    private BlowfishSerializer _serializer;

    public BlowfishTupleSerializer(Kryo kryo, Map storm_conf) {
        String encryption_key = null;
        try {
            encryption_key = (String)storm_conf.get(SECRET_KEY);
            LOG.debug("Blowfish serializer being constructed ...");
            if (encryption_key == null) {
                throw new RuntimeException("Blowfish encryption key not specified");
            }
            byte[] bytes =  Hex.decodeHex(encryption_key.toCharArray());
            _serializer = new BlowfishSerializer(new ListDelegateSerializer(), bytes);
        } catch (org.apache.commons.codec.DecoderException ex) {
            throw new RuntimeException("Blowfish encryption key invalid", ex);
        }
    }

    @Override
    public void write(Kryo kryo, Output output, ListDelegate object) {
        _serializer.write(kryo, output, object);
    }

    @Override
    public ListDelegate read(Kryo kryo, Input input, Class<ListDelegate> type) {
        return (ListDelegate)_serializer.read(kryo, input, type);
    }

    /**
     * Produce a blowfish key to be used in "Storm jar" command
     */
    public static void main(String[] args) {
        try{

View on GitHub (pinned to cdb116e942)