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
- Set heartbeat.interval.ms to roughly one-third of session.timeout.ms (the documented rule of thumb).
- Ensure session.timeout.ms > heartbeat.interval.ms in consumer properties, e.g. session=45000, heartbeat=15000.
- 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
- Rule of thumb: set heartbeat.interval.ms to roughly one-third of session.timeout.ms.
- Centralize consumer config in one builder/validator so this invariant is checked once at startup, not per consumer.
- Bump session.timeout.ms when processing time per batch is long, and proportionally adjust heartbeat.interval.ms.
- Add a unit test asserting heartbeat < session for every config profile shipped in your deployment.
- Avoid copying broker-side keepalive settings into consumer configs; they are independent dials.
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
- User configured {} to empty while trying to subscribe for gr
- Get fenced exception for group.instance.id {}, current membe
- Failed to construct Kafka consumer
- To use the group management or offset commit APIs, you must
- The target time for partition {} is {}. The target time cann
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/1221fe260f850e81.json.
Report an issue: GitHub.