{"record":{"id":"44a7cc0b03b3eeb6","repo":"nathanmarz/storm","slug":"blowfish-encryption-key-not-specified","errorCode":null,"errorMessage":"Blowfish encryption key not specified","messagePattern":"Blowfish encryption key not specified","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"storm-core/src/jvm/backtype/storm/security/serialization/BlowfishTupleSerializer.java","lineNumber":55,"sourceCode":"/**\n * Apply Blowfish encrption for tuple communication to bolts\n */\npublic class BlowfishTupleSerializer extends Serializer<ListDelegate> {\n    /**\n     * The secret key (if any) for data encryption by blowfish payload serialization factory (BlowfishSerializationFactory). \n     * You should use in via \"storm -c topology.tuple.serializer.blowfish.key=YOURKEY -c topology.tuple.serializer=backtype.storm.security.serialization.BlowfishTupleSerializer jar ...\".\n     */\n    public static String SECRET_KEY = \"topology.tuple.serializer.blowfish.key\";\n    private static final Logger LOG = Logger.getLogger(BlowfishTupleSerializer.class);\n    private BlowfishSerializer _serializer;\n\n    public BlowfishTupleSerializer(Kryo kryo, Map storm_conf) {\n        String encryption_key = null;\n        try {\n            encryption_key = (String)storm_conf.get(SECRET_KEY);\n            LOG.debug(\"Blowfish serializer being constructed ...\");\n            if (encryption_key == null) {\n                throw new RuntimeException(\"Blowfish encryption key not specified\");\n            }\n            byte[] bytes =  Hex.decodeHex(encryption_key.toCharArray());\n            _serializer = new BlowfishSerializer(new ListDelegateSerializer(), bytes);\n        } catch (org.apache.commons.codec.DecoderException ex) {\n            throw new RuntimeException(\"Blowfish encryption key invalid\", ex);\n        }\n    }\n\n    @Override\n    public void write(Kryo kryo, Output output, ListDelegate object) {\n        _serializer.write(kryo, output, object);\n    }\n\n    @Override\n    public ListDelegate read(Kryo kryo, Input input, Class<ListDelegate> type) {\n        return (ListDelegate)_serializer.read(kryo, input, type);\n    }\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/backtype/storm/security/serialization/BlowfishTupleSerializer.java#L37-L73","documentation":"BlowfishTupleSerializer encrypts serialized tuples with Kryo's BlowfishSerializer using a hex-encoded key taken from the Storm config key StormBoltEnviroment... specifically its SECRET_KEY config constant (topology.message.transfer...). If storm_conf has no value for that key, the constructor deliberately throws this RuntimeException because encryption without a key is impossible — the serializer cannot be constructed.","triggerScenarios":"Configuring storm.messaging.serializer / topology.tuple.serializer (or the Kryo decorator registration) to BlowfishTupleSerializer without setting the corresponding storm.conf key (SECRETS... 'topology.tuple.secret.key' / 'storm.messaging...secret.key') in storm.yaml; the key was removed during config migration; or the config map passed programmatically omits it.","commonSituations":"Operators enabling encrypted tuple transport per the Storm security docs but forgetting to add the secret key to storm.yaml on workers; upgrading Storm and the old key name no longer matches; building Kryo instances in unit tests with a stripped/minimal conf map.","solutions":["Set the secret key in storm.yaml (the constant referenced by BlowfishTupleSerializer.SECRET_KEY, e.g. 'supervisor...'), as a valid hex string.","Generate a proper hex key, e.g. run 'openssl rand -hex 16' and paste the result under the config key.","Make sure the key is present on all workers (storm.yaml is distributed to every node) so the topology can serialize/deserialize on both ends.","If encryption is not needed, remove the BlowfishTupleSerializer registration instead of registering it without a key."],"exampleFix":"// storm.yaml before\nstorm.messaging.serializer: \"backtype.storm.security.serialization.BlowfishTupleSerializer\"\n// after\nstorm.messaging.serializer: \"backtype.storm.security.serialization.BlowfishTupleSerializer\"\ntopology.tuple.secret.key: \"3f8a1c9d2b7e4f6a1c9d2b7e4f6a1c9d\"","handlingStrategy":"validation","validationCode":"String key = (String) stormConf.get(\"topology.tuple.secret.key\");\nif (key == null || key.isEmpty()) {\n    throw new IllegalArgumentException(\"Blowfish secret key must be set in storm.yaml before using BlowfishTupleSerializer\");\n}\nif (!key.matches(\"[0-9a-fA-F]+\") || key.length() % 2 != 0) {\n    throw new IllegalArgumentException(\"Blowfish secret key must be a valid even-length hex string\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    new BlowfishTupleSerializer(kryo, stormConf);\n} catch (RuntimeException e) {\n    LOG.error(\"Blowfish serializer setup failed: \" + e.getMessage());\n    throw e; // fail fast: continuing would silently disable encryption\n}","preventionTips":["Add the secret-key entry to storm.yaml wherever the Blowfish serializer is registered, and distribute it to every node","Generate keys with 'openssl rand -hex 16' to avoid formatting mistakes","Add a config sanity check to your deployment pipeline that greps storm.yaml for the key when the serializer is enabled","Keep the key out of logs and source control; supply it via secrets management"],"tags":["encryption","kryo","configuration","storm"],"backgroundTag":"missing-required-config-field","analyzedSha":"cdb116e942666973bc4eaa0df098d5bab82739e7","analyzedAt":"2026-09-12T14:30:00.714Z","contentChangedAt":"2026-09-12T14:30:00.714Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}