apache/pulsar · error · IllegalArgumentException
timeout must be > 0
Error message
timeout must be > 0
What it means
TransactionPolicy requires a strictly positive Duration for the transaction timeout. The timeout determines how long a transaction may remain open before the coordinator aborts it; null, zero, or negative values cannot define a valid deadline, so the private constructor throws IllegalArgumentException (null is caught by the preceding requireNonNull).
Source
Thrown at pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/TransactionPolicy.java:40
import java.util.Objects;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* Transaction configuration for the Pulsar client.
*
* <p>Construct via {@link #builder()}.
*/
@EqualsAndHashCode
@ToString
public final class TransactionPolicy {
private final Duration timeout;
private TransactionPolicy(Duration timeout) {
Objects.requireNonNull(timeout, "timeout must not be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("timeout must be > 0");
}
this.timeout = timeout;
}
/**
* @return transaction timeout — if the transaction is not committed or aborted within this duration,
* the broker automatically aborts it
*/
public Duration timeout() {
return timeout;
}
/**
* @return a new builder for constructing a {@link TransactionPolicy}
*/
public static Builder builder() {
return new Builder();
}View on GitHub (pinned to 820761864e)
Solutions
- Pass a positive duration, e.g. .timeout(Duration.ofMinutes(1)) on the TransactionPolicy builder
- If the value comes from config, default to a positive constant when it is missing or <= 0
- Confirm the configured seconds/minutes value is > 0 before wrapping it in a Duration
Example fix
// before
long seconds = config.getProperty("txn.timeout", 0);
TransactionPolicy p = TransactionPolicy.builder().timeout(Duration.ofSeconds(seconds)).build();
// after
long seconds = config.getProperty("txn.timeout", 60);
if (seconds <= 0) seconds = 60;
TransactionPolicy p = TransactionPolicy.builder().timeout(Duration.ofSeconds(seconds)).build(); Defensive patterns
Strategy: validation
Validate before calling
if (timeout == null || timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("transaction timeout must be a positive Duration, got: " + timeout);
} Type guard
boolean isPositive(Duration d) { return d != null && !d.isZero() && !d.isNegative(); } Try / catch
try {
policy = TransactionPolicy.builder().timeout(timeout).build();
} catch (IllegalArgumentException e) {
log.error("Invalid transaction timeout: {}", e.getMessage());
policy = TransactionPolicy.builder().timeout(Duration.ofMinutes(1)).build();
} Prevention
- Never let a config default of 0 flow into a Duration-based timeout
- Clamp parsed values: Math.max(1, configuredSeconds)
- Document that zero means invalid for transaction timeouts (unlike ProcessingTimeoutPolicy)
When it happens
Trigger: Passing Duration.ZERO or a negative Duration to TransactionPolicy's builder/factory; passing null produces the preceding 'timeout must not be null' NPE instead.
Common situations: Config values parsed as 0 (unset property defaulting to 0 seconds), or code computing a timeout that rounds down to zero.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- timeout must not be negative
- Topic name is not valid
- PublishTxnMessage is not supported by non-persistent topic
- timeout must not be null
- at least one key name must be configured
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/d0822d93f4963933.
Report an issue: GitHub.