kestra-io/kestra · error · SecretNotFoundException
Cannot find secret for key '{key}'.
Error message
Cannot find secret for key '{key}'. What it means
The `SecretService.findSecret()` method looks up a secret by its key (case-insensitive, uppercased) in the in-memory `decodedSecrets` map. This map is populated at startup from environment variables prefixed with `SECRET_`. If no matching key exists, a `SecretNotFoundException` is thrown. This is a runtime/infrastructure error, not a code error.
Source
Thrown at core/src/main/java/io/kestra/core/secret/SecretService.java:55
try {
String value = entry.getValue().replaceAll("\\R", "");
consumer.accept(Map.entry(entry.getKey(), new String(Base64.getDecoder().decode(value))));
} catch (Exception e) {
log.error("Could not decode secret '{}', make sure it is Base64-encoded: {}", entry.getKey(), e.getMessage());
}
})
.collect(
Collectors.toMap(
entry -> entry.getKey().substring(SECRET_PREFIX.length()).toUpperCase(),
Map.Entry::getValue
)
);
}
public String findSecret(String tenantId, String namespace, String key) throws SecretNotFoundException, IOException {
String secret = decodedSecrets.get(key.toUpperCase());
if (secret == null) {
throw new SecretNotFoundException("Cannot find secret for key '" + key + "'.");
}
return secret;
}
/**
* Finds the secret in full mode, as a value plus metadata.
* The default returns the value with empty metadata. Multi-field secret managers override this to add metadata.
*/
public SecretObject findSecretObject(String tenantId, String namespace, String key) throws SecretNotFoundException, IOException {
return new SecretObject(findSecret(tenantId, namespace, key));
}
public ArrayListTotal<META> list(Pageable pageable, String tenantId, List<QueryFilter> filters) throws IOException {
final Predicate<String> queryPredicate = filters.stream()
.filter(filter -> QueryFilter.Field.QUERY.equals(filter.field()) && filter.value() != null)
.findFirst()
.map(filter ->
{View on GitHub (pinned to 823fada927)
Solutions
- Verify the secret environment variable is set with the exact prefix: `SECRET_MY_KEY` for key `MY_KEY`.
- Ensure the value is Base64-encoded (the service decodes it; a raw value will fail silently at decode time and the key will be absent).
- Check that the env var is actually present in the running process (`env | grep SECRET_`).
- In Docker/k8s, verify the secret is mounted as an env var in the container spec.
- Confirm there is no tenant/namespace mismatch if using a custom secret manager.
Example fix
# before: secret missing from env
{{ secret('API_KEY') }}
# fix: set the env var with Base64-encoded value
export SECRET_API_KEY=$(echo -n 'my-secret-value' | base64) Defensive patterns
Strategy: try-catch
Validate before calling
// Check if secret key exists before calling findSecret
import io.kestra.core.secret.SecretService;
public static String getSecretOrEmpty(SecretService service, String tenantId, String namespace, String key) {
try {
return service.findSecret(tenantId, namespace, key);
} catch (SecretNotFoundException e) {
return null; // or throw a more descriptive error
}
} Try / catch
try {
String secret = secretService.findSecret(tenantId, namespace, key);
} catch (SecretNotFoundException e) {
log.error("Secret '{}' not found. Ensure SECRET_{} env var is set and Base64-encoded.", key, key.toUpperCase());
throw e;
} Prevention
- Verify secrets are set with `env | grep SECRET_` in the running process.
- Ensure secret values are Base64-encoded in the environment variable.
- Document required secret keys in the flow or README.
- Use a secrets management checklist for deployments.
- In Docker/k8s, verify secrets are mounted as env vars in the container spec.
When it happens
Trigger: Referencing `{{ secret('MY_KEY') }}` in a flow when no `SECRET_MY_KEY` environment variable is set. The secret was deleted from the environment or the variable name has a typo. The secret exists but under a different tenant or namespace (in multi-tenant setups with custom secret managers).
Common situations: Secrets are set in a local `.env` file but not loaded into the running process. In Docker/k8s deployments the secret env var was not mounted into the container. A secret key has a typo or case mismatch (the lookup uppercases the key, but the env var prefix must be `SECRET_`).
Related errors
- Cannot find secret sub-key '%s' in secret '%s'.
- Missing required options '--plugins' or environment variable
- Missing required options '--plugins' or environment variable
- Tenant id can only be 'main'
- No log store configured through the application property '%s
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/ecd4863391edfb96.
Report an issue: GitHub.