elastic/elasticsearch · error · IllegalArgumentException

sniffRequestTimeoutMillis must be greater than 0

Error message

sniffRequestTimeoutMillis must be greater than 0

What it means

Constructor guard on ElasticsearchNodesSniffer: the sniff request timeout passed to /_nodes/http?timeout=Nms must not be negative. Note the message says 'greater than 0' but the actual check is `< 0`, so a value of 0 is currently accepted; only strictly negative values trigger this error.

Source

Thrown at client/sniffer/src/main/java/org/elasticsearch/client/sniff/ElasticsearchNodesSniffer.java:94

    public ElasticsearchNodesSniffer(RestClient restClient) {
        this(restClient, DEFAULT_SNIFF_REQUEST_TIMEOUT, ElasticsearchNodesSniffer.Scheme.HTTP);
    }

    /**
     * Creates a new instance of the Elasticsearch sniffer. It will use the provided {@link RestClient} to fetch the hosts
     * through the nodes info api, the provided sniff request timeout value and scheme.
     * @param restClient client used to fetch the hosts from elasticsearch through nodes info api. Usually the same instance
     *                   that is also provided to {@link Sniffer#builder(RestClient)}, so that the hosts are set to the same
     *                   client that was used to sniff them.
     * @param sniffRequestTimeoutMillis the sniff request timeout (in milliseconds) to be passed in as a query string parameter
     *                                  to elasticsearch. Allows to halt the request without any failure, as only the nodes
     *                                  that have responded within this timeout will be returned.
     * @param scheme the scheme to associate sniffed nodes with (as it is not returned by elasticsearch)
     */
    public ElasticsearchNodesSniffer(RestClient restClient, long sniffRequestTimeoutMillis, Scheme scheme) {
        this.restClient = Objects.requireNonNull(restClient, "restClient cannot be null");
        if (sniffRequestTimeoutMillis < 0) {
            throw new IllegalArgumentException("sniffRequestTimeoutMillis must be greater than 0");
        }
        this.request = new Request("GET", "/_nodes/http");
        request.addParameter("timeout", sniffRequestTimeoutMillis + "ms");
        this.scheme = Objects.requireNonNull(scheme, "scheme cannot be null");
    }

    /**
     * Calls the elasticsearch nodes info api, parses the response and returns all the found http hosts
     */
    @Override
    public List<Node> sniff() throws IOException {
        Response response = restClient.performRequest(request);
        return readHosts(response.getEntity(), scheme, jsonFactory);
    }

    static List<Node> readHosts(HttpEntity entity, Scheme scheme, JsonFactory jsonFactory) throws IOException {
        try (InputStream inputStream = entity.getContent()) {
            JsonParser parser = jsonFactory.createParser(inputStream);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Pass a non-negative value (>=0); use a small positive value like 1000 (1s) for normal sniffing.
  2. Guard against arithmetic that can go negative before constructing the sniffer.
  3. If you want 'no deadline', use 0 explicitly (the message wording is stricter than the code).

Example fix

// before
long timeout = configuredTimeoutMs - elapsedMs; // can be < 0
new ElasticsearchNodesSniffer(client, timeout, Scheme.HTTP);
// after
long timeout = Math.max(0, configuredTimeoutMs - elapsedMs);
new ElasticsearchNodesSniffer(client, timeout, Scheme.HTTP);
Defensive patterns

Strategy: validation

Validate before calling

long t = Math.max(0, configuredTimeoutMs);
new ElasticsearchNodesSniffer(client, t, Scheme.HTTP);

Type guard

sniffRequestTimeoutMillis >= 0

Prevention

When it happens

Trigger: Constructing ElasticsearchNodesSniffer with a negative timeout, or wiring SnifferBuilder defaults through code that computed a negative duration.

Common situations: Computing the timeout as 'configured - elapsed' which went negative under load; passing -1 as a sentinel; misreading the message and supplying 0 when you meant 'no timeout' (0 is allowed and means immediate).

Understand the failure class

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/8e50a52c72daaae8. Report an issue: GitHub.