kestra-io/kestra · error · IllegalArgumentException

Digest authentication requires both `username` and `password

Error message

Digest authentication requires both `username` and `password`.

What it means

Thrown by the Kestra HTTP client when digest authentication is configured but credentials are incomplete. clientContext renders username/password via the run context; if username is empty (after render) or password is null, it throws IllegalArgumentException. Blank-but-non-null password is allowed; only a missing password value triggers it.

Source

Thrown at core/src/main/java/io/kestra/core/http/client/HttpClient.java:478

            .name(eventName)
            .comment(comment)
            .retry(retry)
            .build();

        if (eventConsumer != null) {
            eventConsumer.accept(event);
        }
    }

    private HttpClientContext clientContext(HttpRequest request) throws IllegalVariableEvaluationException {
        HttpClientContext httpClientContext = ContextBuilder.create().build();

        if (this.configuration.getAuth() instanceof DigestAuthConfiguration digestAuthConfiguration) {
            String username = runContext.render(digestAuthConfiguration.getUsername()).as(String.class).orElse(null);
            String password = runContext.render(digestAuthConfiguration.getPassword()).as(String.class).orElse(null);

            if (StringUtils.isEmpty(username) || password == null) {
                throw new IllegalArgumentException("Digest authentication requires both `username` and `password`.");
            }

            URI uri = request.getUri();
            if (uri == null || uri.getHost() == null) {
                throw new IllegalArgumentException("Digest authentication requires an absolute URI with a host.");
            }

            int port = uri.getPort() != -1 ? uri.getPort() : ("https".equalsIgnoreCase(uri.getScheme()) ? 443 : 80);
            AuthScope digestScope = new AuthScope(uri.getHost(), port);
            UsernamePasswordCredentials digestCredentials = new UsernamePasswordCredentials(username, password.toCharArray());

            httpClientContext.setCredentialsProvider((authScope, context) ->
            {
                if (digestScope.match(authScope) >= 0) {
                    return digestCredentials;
                }
                return this.defaultCredentialsProvider.getCredentials(authScope, context);
            });

View on GitHub (pinned to 823fada927)

Solutions

  1. Provide both username and password in the digest auth configuration.
  2. If using secret expressions ({{ secret('USER') }}), confirm the secret exists and resolves to a non-empty value.
  3. Double-check the property names match DigestAuthConfiguration (username, password).
  4. Test the rendered value with a debug log or a no-op task that prints the resolved length.

Example fix

# before
- id: http
  type: io.kestra.plugin.core.http.Request
  auth:
    type: digest
    username: "{{ secret('API_USER') }}"
    # password missing
# after
- id: http
  type: io.kestra.plugin.core.http.Request
  auth:
    type: digest
    username: "{{ secret('API_USER') }}"
    password: "{{ secret('API_PASS') }}"
Defensive patterns

Strategy: validation

Validate before calling

String username = runContext.render(digestAuthConfiguration.getUsername()).as(String.class).orElse(null);
String password = runContext.render(digestAuthConfiguration.getPassword()).as(String.class).orElse(null);
if (StringUtils.isEmpty(username) || password == null) {
  throw new IllegalStateException('Digest auth requires both username and password; check secret resolution');
}

Try / catch

try {
  // build httpClientContext with digest creds
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains('username') || e.getMessage().contains('password')) {
    log.error('Digest auth misconfigured: {}', e.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: Task uses HttpClient with auth.type=digest; runContext.render(digestAuthConfiguration.getUsername()).as(String) yields empty OR runContext.render(password).as(String) yields null; the StringUtils.isEmpty(username) || password == null guard throws.

Common situations: Username/password secret not resolved (missing secret), the rendered expression evaluates to empty, a typo in the property name, or the password field omitted from the task config.

Understand the failure class

Related errors


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