elastic/elasticsearch · error · IllegalArgumentException

sniffAfterFailureDelayMillis must be greater than 0

Error message

sniffAfterFailureDelayMillis must be greater than 0

What it means

SnifferBuilder guard: the delay before a failure-triggered sniff must be strictly positive. Zero or negative would make the post-failure sniff fire instantly (or never), defeating the purpose of a short recovery delay.

Source

Thrown at client/sniffer/src/main/java/org/elasticsearch/client/sniff/SnifferBuilder.java:65

    /**
     * Sets the interval between consecutive ordinary sniff executions in milliseconds. Will be honoured when
     * sniffOnFailure is disabled or when there are no failures between consecutive sniff executions.
     * @throws IllegalArgumentException if sniffIntervalMillis is not greater than 0
     */
    public SnifferBuilder setSniffIntervalMillis(int sniffIntervalMillis) {
        if (sniffIntervalMillis <= 0) {
            throw new IllegalArgumentException("sniffIntervalMillis must be greater than 0");
        }
        this.sniffIntervalMillis = sniffIntervalMillis;
        return this;
    }

    /**
     * Sets the delay of a sniff execution scheduled after a failure (in milliseconds)
     */
    public SnifferBuilder setSniffAfterFailureDelayMillis(int sniffAfterFailureDelayMillis) {
        if (sniffAfterFailureDelayMillis <= 0) {
            throw new IllegalArgumentException("sniffAfterFailureDelayMillis must be greater than 0");
        }
        this.sniffAfterFailureDelayMillis = sniffAfterFailureDelayMillis;
        return this;
    }

    /**
     * Sets the {@link NodesSniffer} to be used to read hosts. A default instance of {@link ElasticsearchNodesSniffer}
     * is created when not provided. This method can be used to change the configuration of the {@link ElasticsearchNodesSniffer},
     * or to provide a different implementation (e.g. in case hosts need to taken from a different source).
     */
    public SnifferBuilder setNodesSniffer(NodesSniffer nodesSniffer) {
        Objects.requireNonNull(nodesSniffer, "nodesSniffer cannot be null");
        this.nodesSniffer = nodesSniffer;
        return this;
    }

    /**
     * Creates the {@link Sniffer} based on the provided configuration.

View on GitHub (pinned to db6a809a66)

Solutions

  1. Pass a positive value in milliseconds, e.g. 60000 (1 minute) which matches the default.
  2. Validate config-derived delays before calling the setter.
  3. Confirm the unit (milliseconds) and that the source value is non-zero.

Example fix

// before
Sniffer.builder(client).setSniffAfterFailureDelayMillis(delaySec).build(); // 0 or wrong unit
// after
Sniffer.builder(client).setSniffAfterFailureDelayMillis(Math.max(1, delaySec * 1000)).build();
Defensive patterns

Strategy: validation

Validate before calling

if (delayMs <= 0) throw new IllegalArgumentException("sniffAfterFailureDelayMillis must be > 0; got " + delayMs);
Sniffer.builder(client).setSniffAfterFailureDelayMillis(delayMs);

Type guard

sniffAfterFailureDelayMillis > 0

Prevention

When it happens

Trigger: Calling Sniffer.builder(client).setSniffAfterFailureDelayMillis(0) or a value computed to <= 0.

Common situations: Config-driven delay left unset then defaulted to 0; arithmetic that produced a non-positive value; passing seconds instead of milliseconds.

Related errors


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