kestra-io/kestra · error · IllegalArgumentException
The URI {} is not in the configured allowed list (kestra.tas
Error message
The URI {} is not in the configured allowed list (kestra.tasks.http.allowed-list). What it means
Thrown by the Kestra HTTP client when an allow-list is configured (kestra.tasks.http.allowed-list) and the request URI does not start with any allowed prefix. validateUri reads the allowed-list task property; if non-empty and no entry matches requestUri.startsWith, it throws IllegalArgumentException naming the offending URI. This is a security control preventing SSRF.
Source
Thrown at core/src/main/java/io/kestra/core/http/client/HttpClient.java:558
if (e.getCause() instanceof HttpClientException httpClientException) {
throw httpClientException;
}
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
private void validateUri(URI uri) {
String requestUri = uri.toString();
List<String> allowedList = (List<String>) ((DefaultRunContext) runContext).getTaskProperty("kestra.tasks.http.allowed-list", List.class).orElse(Collections.emptyList());
List<String> deniedList = (List<String>) ((DefaultRunContext) runContext).getTaskProperty("kestra.tasks.http.denied-list", List.class).orElse(Collections.emptyList());
// first check that if there is an allow list, it matches one
if (!allowedList.isEmpty()) {
if (allowedList.stream().noneMatch(requestUri::startsWith)) {
throw new IllegalArgumentException("The URI " + requestUri + " is not in the configured allowed list (kestra.tasks.http.allowed-list).");
}
}
// then check that there are no exclusion for it
if (deniedList.stream().anyMatch(requestUri::startsWith)) {
throw new IllegalArgumentException("The URI " + requestUri + " is in the configured denied list (kestra.tasks.http.denied-list).");
}
}
@SuppressWarnings("unchecked")
private <T> T bodyHandler(Class<?> cls, HttpEntity entity) throws IOException, ParseException {
if (entity == null) {
return null;
} else if (String.class.isAssignableFrom(cls)) {
return (T) EntityUtils.toString(entity);
} else if (Byte[].class.isAssignableFrom(cls)) {
return (T) ArrayUtils.toObject(EntityUtils.toByteArray(entity));
} else if (MediaType.APPLICATION_YAML.equals(entity.getContentType()) || "application/yaml".equals(entity.getContentType())) {View on GitHub (pinned to 823fada927)
Solutions
- Add the request URI's scheme+host (and path prefix) to kestra.tasks.http.allowed-list.
- Ensure the prefix match includes the scheme, e.g. 'https://api.example.com'.
- If the URI is dynamic, constrain the expression so it only resolves to allowed hosts.
- Review whether the allow-list should be relaxed or the task retargeted to an approved host.
Example fix
# before
kestra:
tasks:
http:
allowed-list:
- "https://api.example.com/"
# task calls https://api.other.com -> rejected
# after
kestra:
tasks:
http:
allowed-list:
- "https://api.example.com/"
- "https://api.other.com/" Defensive patterns
Strategy: validation
Validate before calling
List<String> allowed = getTaskProperty('kestra.tasks.http.allowed-list', List.class).orElse(List.of());
if (!allowed.isEmpty() && allowed.stream().noneMatch(uri.toString()::startsWith)) {
throw new IllegalStateException('URI not in allowed-list: ' + uri);
} Try / catch
try {
validateUri(uri);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains('allowed list')) {
log.error('Allow-list rejected {}', uri);
}
throw e;
} Prevention
- Maintain the allowed-list with full scheme+host prefixes.
- Constrain dynamic URIs so they cannot leave the allow-list.
- Review allow-list changes in security review.
When it happens
Trigger: Task property kestra.tasks.http.allowed-list is a non-empty list; validateUri(request.uri) finds allowedList.stream().noneMatch(requestUri::startsWith); IllegalArgumentException is thrown.
Common situations: Allowed-list was tightened and the task targets a host not in it, the URI scheme changed (http vs https), a dynamic URI resolved to an unexpected host, or the allow-list prefix was typo'd.
Related errors
- The URI {} is in the configured denied list (kestra.tasks.ht
- Digest authentication requires both `username` and `password
- Digest authentication requires an absolute URI with a host.
- Both username and password must be provided if either is pre
- The file:// protocol has been disabled inside the Kestra con
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/7bf1c197779378c6.
Report an issue: GitHub.