apache/cassandra · critical · RuntimeException
couldn't load cipher factory
Error message
couldn't load cipher factory
What it means
The CipherFactory constructor resolves the configured TDE key provider class via reflection and instantiates it with the TransparentDataEncryptionOptions. Any failure (class missing, no matching constructor, constructor throwing) is wrapped in a RuntimeException with this message.
Solutions
- Check transparent_data_encryption_options.key_provider.class_name spelling; default is org.apache.cassandra.security.JKSKeyProvider.
- Ensure the class implements org.apache.cassandra.security.KeyProvider and has a public constructor taking TransparentDataEncryptionOptions.
- If using a custom provider, add its JAR to the classpath (lib/ or classpath config).
- Inspect the wrapped cause for the underlying error (ClassNotFoundException vs constructor exception).
Example fix
// before (cassandra.yaml)
transparent_data_encryption_options:
key_provider:
class_name: com.example.MyKeyProviser
// after
transparent_data_encryption_options:
key_provider:
class_name: com.example.MyKeyProvider Defensive patterns
Strategy: validation
Validate before calling
String cn = tdeOptions.key_provider.class_name; Class<?> c = Class.forName(cn); if (!KeyProvider.class.isAssignableFrom(c)) throw new IllegalArgumentException(cn + " is not a KeyProvider"); c.getConstructor(TransparentDataEncryptionOptions.class); // throws NoSuchMethodException early
Try / catch
try {
new CipherFactory(tdeOptions);
} catch (RuntimeException e) {
throw new ConfigurationException("Invalid key_provider settings: " + e.getCause(), e);
} Prevention
- Copy-paste fully-qualified class names, don't hand-type them
- Ship custom key provider JARs and verify with a startup smoke test
- Keep default JKSKeyProvider unless a custom provider is truly needed
When it happens
Trigger: new CipherFactory(options) where options.key_provider.class_name does not exist on the classpath, is not a KeyProvider, has no (TransparentDataEncryptionOptions) constructor, or its constructor throws (e.g. bad JCEKS path).
Common situations: Typo in cipher/key_provider class_name in cassandra.yaml, custom key provider JAR not shipped in lib/, key provider constructor failing to open the keystore file.
Related errors
- a hints file cannot be configured for both compression and…
- Cannot find configured row cache provider class
- cannot load cipher
- commitlog_disk_access_mode =
- Error constructing replication strategy class
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/c196720470a6ca3c.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/security/CipherFactory.java:82
private final int ivLength;
private final KeyProvider keyProvider;
public CipherFactory(TransparentDataEncryptionOptions options)
{
logger.info("initializing CipherFactory");
ivLength = options.iv_length;
try
{
secureRandom = SecureRandom.getInstance("SHA1PRNG");
Class<? extends KeyProvider> keyProviderClass =
FBUtilities.classForNameWithoutInitialization(options.key_provider.class_name, "key provider", KeyProvider.class);
Constructor<? extends KeyProvider> ctor = keyProviderClass.getConstructor(TransparentDataEncryptionOptions.class);
keyProvider = ctor.newInstance(options);
}
catch (Exception e)
{
throw new RuntimeException("couldn't load cipher factory", e);
}
cache = Caffeine.newBuilder() // by default cache is unbounded
.maximumSize(64) // a value large enough that we should never even get close (so nothing gets evicted)
.executor(ImmediateExecutor.INSTANCE)
.removalListener((key, value, cause) ->
{
// maybe reload the key? (to avoid the reload being on the user's dime)
logger.info("key {} removed from cipher key cache", key);
})
.build(alias ->
{
logger.info("loading secret key for alias {}", alias);
return keyProvider.getSecretKey(alias);
});
}
public Cipher getEncryptor(String transformation, String keyAlias) throws IOExceptionView on GitHub (pinned to 88fd0f6a0e)