aeron-io/aeron · error · IllegalArgumentException

newLeaderTimeoutNs must be positive or -1, but was

Error message

newLeaderTimeoutNs must be positive or -1, but was <newLeaderTimeoutNs>

What it means

newLeaderTimeoutNs controls how long the client waits for a new leader before failing. Context.newLeaderTimeoutNs() validates the value with IllegalArgumentException: it must be strictly positive or the NULL_VALUE (-1) sentinel meaning use the default; zero and other negatives are rejected.

Solutions

  1. Pass a positive value in nanoseconds, e.g. TimeUnit.SECONDS.toNanos(30)
  2. Pass AeronCluster.NULL_VALUE (-1) to accept the library default
  3. Fix config parsing so 0/negative inputs map to the default rather than being forwarded

Example fix

// before
long timeout = config.getTimeoutMs(); // may be 0
ctx.newLeaderTimeoutNs(timeout);
// after
long timeoutMs = config.getTimeoutMs();
long timeoutNs = timeoutMs > 0 ? TimeUnit.MILLISECONDS.toNanos(timeoutMs) : AeronCluster.NULL_VALUE;
ctx.newLeaderTimeoutNs(timeoutNs);
Defensive patterns

Strategy: validation

Validate before calling

long ns = configuredTimeout;
if (!(ns > 0 || ns == AeronCluster.NULL_VALUE)) {
    throw new IllegalArgumentException("newLeaderTimeoutNs must be positive or NULL_VALUE(-1), got " + ns);
}
ctx.newLeaderTimeoutNs(ns);

Prevention

When it happens

Trigger: Calling ctx.newLeaderTimeoutNs(0) or any negative value other than -1 (NULL_VALUE).

Common situations: Passing a timeout in different units that rounds to 0; using 0 to mean 'no wait' (not supported); computing the value from config where 0/null handling goes wrong.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/71fe4338130e569c. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/client/AeronCluster.java:1600

        @Config
        public long messageTimeoutNs()
        {
            return CommonContext.checkDebugTimeout(messageTimeoutNs, TimeUnit.NANOSECONDS);
        }

        /**
         * The timeout to wait for a new leader after noticing a disconnection from the previous one. Upon timeout the
         * cluster will be considered lost and the client will close. If set to {@link Aeron#NULL_VALUE}, a reasonable
         * default will be used.
         *
         * @param newLeaderTimeoutNs the new leader timeout in nanoseconds or {@link Aeron#NULL_VALUE}.
         * @return this for a fluent API.
         */
        public Context newLeaderTimeoutNs(final long newLeaderTimeoutNs)
        {
            if (!(0 < newLeaderTimeoutNs || NULL_VALUE == newLeaderTimeoutNs))
            {
                throw new IllegalArgumentException(
                    "newLeaderTimeoutNs must be positive or -1, but was " + newLeaderTimeoutNs);
            }
            this.newLeaderTimeoutNs = newLeaderTimeoutNs;
            return this;
        }

        /**
         * The timeout to wait for a new leader after noticing a disconnection from the previous one. Upon timeout the
         * cluster will be considered lost and the client will close.
         *
         * @return the new leader timeout in nanoseconds.
         */
        public long newLeaderTimeoutNs()
        {
            return CommonContext.checkDebugTimeout(newLeaderTimeoutNs, TimeUnit.NANOSECONDS);
        }

        /**

View on GitHub (pinned to 6d60124e15)