apache/kafka · error · IllegalArgumentException

Heartbeat must be set lower than the session timeout

Error message

Heartbeat must be set lower than the session timeout

What it means

IllegalArgumentException from the Heartbeat constructor validating that heartbeat.interval.ms is strictly less than session.timeout.ms. If the heartbeat fires as often as or more often than the session window, the protocol invariant that heartbeats keep the member alive within one session would be violated. The check runs once at consumer construction, so the failure surfaces immediately when the consumer is built rather than at runtime.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/Heartbeat.java:48

 */
public final class Heartbeat {
    private final int maxPollIntervalMs;
    private final GroupRebalanceConfig rebalanceConfig;
    private final Time time;
    private final Timer heartbeatTimer;
    private final Timer sessionTimer;
    private final Timer pollTimer;
    private final Logger log;
    private final ExponentialBackoff retryBackoff;

    private volatile long lastHeartbeatSend = 0L;
    private volatile boolean heartbeatInFlight = false;
    private volatile long heartbeatAttempts = 0L;

    public Heartbeat(GroupRebalanceConfig config,
                     Time time) {
        if (config.heartbeatIntervalMs >= config.sessionTimeoutMs)
            throw new IllegalArgumentException("Heartbeat must be set lower than the session timeout");
        this.rebalanceConfig = config;
        this.time = time;
        this.heartbeatTimer = time.timer(config.heartbeatIntervalMs);
        this.sessionTimer = time.timer(config.sessionTimeoutMs);
        this.maxPollIntervalMs = config.rebalanceTimeoutMs;
        this.pollTimer = time.timer(maxPollIntervalMs);
        this.retryBackoff = new ExponentialBackoff(rebalanceConfig.retryBackoffMs,
                CommonClientConfigs.RETRY_BACKOFF_EXP_BASE,
                rebalanceConfig.retryBackoffMaxMs,
                CommonClientConfigs.RETRY_BACKOFF_JITTER);

        final LogContext logContext = new LogContext("[Heartbeat groupID=" + config.groupId + "] ");
        this.log = logContext.logger(getClass());
    }

    private void update(long now) {
        heartbeatTimer.update(now);
        sessionTimer.update(now);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Set heartbeat.interval.ms to roughly one-third of session.timeout.ms (the documented rule of thumb).
  2. Ensure session.timeout.ms > heartbeat.interval.ms in consumer properties, e.g. session=45000, heartbeat=15000.
  3. Remove explicit heartbeat.interval.ms and let the client compute its default relative to session.timeout.ms.

Example fix

// before
props.put("session.timeout.ms", "10000");
props.put("heartbeat.interval.ms", "10000");

// after
props.put("session.timeout.ms", "45000");
props.put("heartbeat.interval.ms", "15000");
Defensive patterns

Strategy: validation

Validate before calling

long heartbeatMs = (Long) props.getOrDefault("heartbeat.interval.ms", 3000L);
long sessionMs  = (Long) props.getOrDefault("session.timeout.ms", 45000L);
if (heartbeatMs >= sessionMs) {
    throw new IllegalArgumentException(
        "heartbeat.interval.ms (" + heartbeatMs + ") must be strictly less than session.timeout.ms (" + sessionMs + ")");
}

Type guard

private static boolean heartbeatFitsSession(long heartbeatMs, long sessionMs) {
    return heartbeatMs > 0 && sessionMs > 0 && heartbeatMs < sessionMs;
}

Prevention

When it happens

Trigger: Thrown when constructing a KafkaConsumer (or otherwise instantiating Heartbeat with a GroupRebalanceConfig) where heartbeat.intervalMs >= sessionTimeoutMs. Common when both are set explicitly in properties to equal or inverting values.

Common situations: Manual tuning of session.timeout.ms without also adjusting heartbeat.interval.ms; copy-pasted config that lowers session.timeout.ms for faster rebalance detection below the heartbeat interval; unit tests that construct Heartbeat directly with synthetic values.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/1221fe260f850e81.json. Report an issue: GitHub.