kestra-io/kestra · error · PebbleException
GeneralSecurityException: e.getMessage()
Error message
GeneralSecurityException: e.getMessage()
What it means
Thrown by the Pebble 'encrypt' template function when EncryptionService.encrypt(key, plaintext) raises a GeneralSecurityException. Unlike decrypt(), a clean encrypt rarely fails on data, so this almost always indicates an invalid key: wrong length, non-ASCII/unexpected bytes, or a key that the AES key-derivation/initialization step rejects.
Source
Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/EncryptFunction.java:40
public Map<String, String> getArgumentDefaults() {
return Map.of(
"key", SecretFunction.NAME + "('encryption_key')",
"plaintext", "'value_to_encrypt'"
);
}
@Override
public Object execute(Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
if (!args.containsKey("key") || !args.containsKey("plaintext")) {
throw new PebbleException(null, "The 'encrypt' function expects two arguments 'key' and 'plaintext'.", lineNumber, self.getName());
}
String key = (String) args.get("key");
String plaintext = (String) args.get("plaintext");
try {
return EncryptionService.encrypt(key, plaintext);
} catch (GeneralSecurityException e) {
throw new PebbleException(e, e.getMessage(), lineNumber, self.getName());
}
}
}
View on GitHub (pinned to 823fada927)
Solutions
- Use a key that is exactly 16, 24, or 32 characters/bytes long to satisfy AES key constraints.
- Confirm secret('encryption_key') resolves to a non-empty value by printing it in a throwaway debug task or via a dedicated check.
- Generate the key once and store it as a Kestra secret, then reference it consistently via the same secret() expression.
- Round-trip encrypt() then decrypt() in a test task to confirm the key is accepted.
Example fix
# before - arbitrary short password fails AES key init
enc: "{{ encrypt('pw', value) }}"
# after - proper-length key from a secret
enc: "{{ encrypt(secret('ENCRYPTION_KEY'), value) }}" Defensive patterns
Strategy: validation
Validate before calling
# Ensure the key resolves to a non-empty string of a valid AES length (16/24/32) before encrypting.
# {{ (secret('ENCRYPTION_KEY') != null and secret('ENCRYPTION_KEY').length in [16,24,32]) ? encrypt(secret('ENCRYPTION_KEY'), value) : null }} Try / catch
# In a wrapper task (Java):
# try { return EncryptionService.encrypt(key, plaintext); }
# catch (GeneralSecurityException e) { /* surface key-length/validity error */ } Prevention
- Use a 16/24/32-character key generated once and stored as a secret.
- Verify secret() resolves to a non-empty value before use.
- Avoid arbitrary passwords/UUIDs as AES keys without proper-length handling.
- Test the key with a round-trip encrypt/decrypt.
When it happens
Trigger: Passing a key whose length is not a valid AES key size; passing a key that contains characters that break key derivation; passing a null resolved by a missing secret; providing a key that is an empty string after secret resolution.
Common situations: Using a short or arbitrary password as the AES key instead of a proper 16/24/32-char key; a secret() expression resolving to empty because the secret does not exist or is in another namespace; passing a UUID or sentence as the key.
Related errors
- GeneralSecurityException: e.getMessage()
- The 'encrypt' function expects two arguments 'key' and 'plai
- The file:// protocol has been disabled inside the Kestra con
- The 'decrypt' function expects two arguments 'key' and 'encr
- Path must not contain '../'
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/a62a72dbefebb9d3.
Report an issue: GitHub.