apache/pulsar · error · IllegalArgumentException

timeout must not be null

Error message

timeout must not be null

What it means

ProcessingTimeoutPolicy's private constructor validates that the processing timeout is non-null before creating the policy object. The Apache Pulsar v5 client API requires an explicit, finite timeout for message processing/redelivery; a null timeout would leave the policy in an undefined state, so the builder rejects it eagerly with IllegalArgumentException.

Source

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

 *
 * <p>Disabled by default. Pass to
 * {@link org.apache.pulsar.client.api.v5.QueueConsumerBuilder#processingTimeout(ProcessingTimeoutPolicy)}
 * when the application's processing time is bounded and you want stalled deliveries to
 * be reattempted automatically.
 *
 * <p>Use {@link #of(Duration)} for the common case (no extra backoff), or
 * {@link #builder()} to also configure {@code redeliveryBackoff}.
 */
@EqualsAndHashCode
@ToString
public final class ProcessingTimeoutPolicy {

    private final Duration timeout;
    private final BackoffPolicy redeliveryBackoff;

    private ProcessingTimeoutPolicy(Duration timeout, BackoffPolicy redeliveryBackoff) {
        if (timeout == null) {
            throw new IllegalArgumentException("timeout must not be null");
        }
        if (timeout.isNegative()) {
            throw new IllegalArgumentException("timeout must not be negative");
        }
        this.timeout = timeout;
        this.redeliveryBackoff = redeliveryBackoff;
    }

    /**
     * @return how long the client waits for the application to ack a delivery before
     *         requesting redelivery; {@link Duration#ZERO} disables
     */
    public Duration timeout() {
        return timeout;
    }

    /**
     * @return optional backoff applied between redeliveries, or {@code null} for the

View on GitHub (pinned to 820761864e)

Solutions

  1. Call .timeout(Duration.ofSeconds(30)) (or your desired duration) on the ProcessingTimeoutPolicy builder before build()
  2. If the timeout comes from configuration, supply a default when the config value is missing, e.g. Objects.requireNonNullElse(configured, Duration.ofSeconds(30))

Example fix

// before
ProcessingTimeoutPolicy policy = ProcessingTimeoutPolicy.builder().build();
// after
ProcessingTimeoutPolicy policy = ProcessingTimeoutPolicy.builder()
        .timeout(Duration.ofSeconds(30))
        .build();
Defensive patterns

Strategy: validation

Validate before calling

if (timeout == null) {
    throw new IllegalArgumentException("ProcessingTimeoutPolicy requires a timeout; pass e.g. Duration.ofSeconds(30)");
}
ProcessingTimeoutPolicy.builder().timeout(timeout).build();

Type guard

boolean hasValidTimeout(Duration d) { return d != null && !d.isNegative(); }

Try / catch

try {
    policy = ProcessingTimeoutPolicy.builder().timeout(timeout).build();
} catch (IllegalArgumentException e) {
    log.error("Invalid processing timeout policy: {}", e.getMessage());
    policy = ProcessingTimeoutPolicy.builder().timeout(Duration.ofSeconds(30)).build();
}

Prevention

When it happens

Trigger: Calling ProcessingTimeoutPolicy.builder().build() or of(null) (any factory/builder path) without ever setting a timeout via .timeout(Duration) so that the private constructor receives a null Duration.

Common situations: Developers copying a builder snippet but omitting the .timeout(...) call, or passing a Duration field that is null because it was read from an unset config property.

Understand the failure class

Related errors


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