{"record":{"id":"3a44e8367d4995d2","repo":"apache/pulsar","slug":"multiplier-must-be-1-0","errorCode":null,"errorMessage":"multiplier must be >= 1.0","messagePattern":"multiplier must be >= 1\\.0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/BackoffPolicy.java","lineNumber":52,"sourceCode":" * the common cases, or {@link #builder()} to configure all knobs explicitly.\n */\n@EqualsAndHashCode\n@ToString\npublic final class BackoffPolicy {\n\n    /** Default jitter percentage applied when not explicitly specified. */\n    public static final double DEFAULT_JITTER_PERCENT = 10.0;\n\n    private final Duration initialInterval;\n    private final Duration maxInterval;\n    private final double multiplier;\n    private final double jitterPercent;\n\n    private BackoffPolicy(Duration initialInterval, Duration maxInterval, double multiplier, double jitterPercent) {\n        Objects.requireNonNull(initialInterval, \"initialInterval must not be null\");\n        Objects.requireNonNull(maxInterval, \"maxInterval must not be null\");\n        if (multiplier < 1.0) {\n            throw new IllegalArgumentException(\"multiplier must be >= 1.0\");\n        }\n        if (jitterPercent < 0 || jitterPercent > 100) {\n            throw new IllegalArgumentException(\"jitterPercent must be in [0, 100]\");\n        }\n        this.initialInterval = initialInterval;\n        this.maxInterval = maxInterval;\n        this.multiplier = multiplier;\n        this.jitterPercent = jitterPercent;\n    }\n\n    /**\n     * @return the base delay before the first reconnection attempt\n     */\n    public Duration initialInterval() {\n        return initialInterval;\n    }\n\n    /**","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/BackoffPolicy.java#L34-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the multiplier to 1.0 or greater — typical exponential backoff uses 2.0.","Use multiplier 1.0 if you want constant-interval retries with only jitter variation.","Clamp the configured value in your config layer: Math.max(1.0, configuredMultiplier) before handing it to the builder."],"exampleFix":"// before\nBackoffPolicy policy = BackoffPolicy.builder()\n    .initialInterval(Duration.ofMillis(100))\n    .maxInterval(Duration.ofSeconds(10))\n    .multiplier(0.5)   // IllegalArgumentException\n    .build();\n// after\nBackoffPolicy policy = BackoffPolicy.builder()\n    .initialInterval(Duration.ofMillis(100))\n    .maxInterval(Duration.ofSeconds(10))\n    .multiplier(2.0)\n    .build();","handlingStrategy":"validation","validationCode":"double multiplier = readConfig(\"retry.multiplier\");\nif (multiplier < 1.0)\n    throw new IllegalArgumentException(\"retry.multiplier must be >= 1.0, got \" + multiplier);\nBackoffPolicy policy = BackoffPolicy.builder().multiplier(multiplier).build();","typeGuard":"static boolean isValidMultiplier(double m) {\n    return m >= 1.0;\n}","tryCatchPattern":"try {\n    policy = BackoffPolicy.builder()\n        .initialInterval(init).maxInterval(max).multiplier(cfg.multiplier()).build();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"multiplier must be >= 1.0\")) {\n        policy = BackoffPolicy.builder()\n            .initialInterval(init).maxInterval(max).multiplier(2.0).build(); // safe default\n    } else throw e;\n}","preventionTips":["Clamp configured multipliers with Math.max(1.0, value) at config load time.","Use 2.0 as the standard exponential factor; use 1.0 for constant-interval retries.","Add a validation unit test covering the boundary values 0.99 (rejected) and 1.0 (accepted)."],"tags":["retry","backoff","illegal-argument","configuration"],"backgroundTag":"invalid-configuration-value","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}