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
- Replace the key with a valid even-length hex string (characters 0-9a-f only), e.g. generate one with 'openssl rand -hex 16'.
- Strip quotes, whitespace, and newlines from the value in storm.yaml.
- Keep the key at a reasonable length ( Blowfish supports 32–448 bit keys, so 8–56 hex-decoded bytes).
- 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
- Always generate the key with a hex-producing tool (openssl rand -hex) instead of hand-writing one
- Trim whitespace and remove surrounding quotes when embedding the key in storm.yaml
- Hex-decode the configured key in a deployment smoke test before rolling out
- Keep key length in the Blowfish-legal range (8–56 bytes after decoding)
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
- Blowfish encryption key not specified
- Could not find a ' ' entry in this configuration: Client…
- Could not find a ' ' entry in this configuration: Server…
- Unable to create serializer
- Cannot set serializations for a component using fluent API
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)