apache/pulsar · error · IllegalArgumentException

multiplier must be >= 1.0

Error message

multiplier must be >= 1.0

What it means

BackoffPolicy's private constructor validates its parameters: a multiplier strictly below 1.0 throws IllegalArgumentException('multiplier must be >= 1.0'). The multiplier is the exponential growth factor applied to each retry interval; a factor under 1.0 would shrink intervals every attempt, producing an ever-faster (and effectively infinite-rate) retry loop, so the builder rejects it up front.

Source

Thrown at pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/BackoffPolicy.java:52

 * the common cases, or {@link #builder()} to configure all knobs explicitly.
 */
@EqualsAndHashCode
@ToString
public final class BackoffPolicy {

    /** Default jitter percentage applied when not explicitly specified. */
    public static final double DEFAULT_JITTER_PERCENT = 10.0;

    private final Duration initialInterval;
    private final Duration maxInterval;
    private final double multiplier;
    private final double jitterPercent;

    private BackoffPolicy(Duration initialInterval, Duration maxInterval, double multiplier, double jitterPercent) {
        Objects.requireNonNull(initialInterval, "initialInterval must not be null");
        Objects.requireNonNull(maxInterval, "maxInterval must not be null");
        if (multiplier < 1.0) {
            throw new IllegalArgumentException("multiplier must be >= 1.0");
        }
        if (jitterPercent < 0 || jitterPercent > 100) {
            throw new IllegalArgumentException("jitterPercent must be in [0, 100]");
        }
        this.initialInterval = initialInterval;
        this.maxInterval = maxInterval;
        this.multiplier = multiplier;
        this.jitterPercent = jitterPercent;
    }

    /**
     * @return the base delay before the first reconnection attempt
     */
    public Duration initialInterval() {
        return initialInterval;
    }

    /**

View on GitHub (pinned to 820761864e)

Solutions

  1. Set the multiplier to 1.0 or greater — typical exponential backoff uses 2.0.
  2. Use multiplier 1.0 if you want constant-interval retries with only jitter variation.
  3. Clamp the configured value in your config layer: Math.max(1.0, configuredMultiplier) before handing it to the builder.

Example fix

// before
BackoffPolicy policy = BackoffPolicy.builder()
    .initialInterval(Duration.ofMillis(100))
    .maxInterval(Duration.ofSeconds(10))
    .multiplier(0.5)   // IllegalArgumentException
    .build();
// after
BackoffPolicy policy = BackoffPolicy.builder()
    .initialInterval(Duration.ofMillis(100))
    .maxInterval(Duration.ofSeconds(10))
    .multiplier(2.0)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

double multiplier = readConfig("retry.multiplier");
if (multiplier < 1.0)
    throw new IllegalArgumentException("retry.multiplier must be >= 1.0, got " + multiplier);
BackoffPolicy policy = BackoffPolicy.builder().multiplier(multiplier).build();

Type guard

static boolean isValidMultiplier(double m) {
    return m >= 1.0;
}

Try / catch

try {
    policy = BackoffPolicy.builder()
        .initialInterval(init).maxInterval(max).multiplier(cfg.multiplier()).build();
} catch (IllegalArgumentException e) {
    if (e.getMessage().equals("multiplier must be >= 1.0")) {
        policy = BackoffPolicy.builder()
            .initialInterval(init).maxInterval(max).multiplier(2.0).build(); // safe default
    } else throw e;
}

Prevention

When it happens

Trigger: Calling BackoffPolicy builder/withMultiplier(0.5) (or any value < 1.0) before the policy is constructed — the private constructor runs on build(), so the exception surfaces there.

Common situations: Confusing multiplier semantics (expecting a decay factor like 0.5 to 'slow down'); porting jitter/backoff constants from another library where the factor was expressed differently; typos such as 0.1 intended as a 10% growth written as an absolute value.

Understand the failure class

Background: "Invalid configuration value" and "Unsupported/Unknown setting value" errors: why libraries reject your config strings, numbers, and types — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/3a44e8367d4995d2. Report an issue: GitHub.