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

  1. Add the request URI's scheme+host (and path prefix) to kestra.tasks.http.allowed-list.
  2. Ensure the prefix match includes the scheme, e.g. 'https://api.example.com'.
  3. If the URI is dynamic, constrain the expression so it only resolves to allowed hosts.
  4. 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

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


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/7bf1c197779378c6. Report an issue: GitHub.