nats-io/nats-server · error · JSStreamInvalidConfigError
flow control ack policy heartbeat needs to be 1s
Error message
flow control ack policy heartbeat needs to be 1s
What it means
When a consumer's AckPolicy is flow-control-based (acked flow control, paired with source/sourcing consumers), the server requires config.Heartbeat to be exactly sourceHealthHB (1s), because heartbeats are also used to detect stalled ephemeral sourcing consumers. Any other heartbeat interval is rejected with this JSStreamInvalidConfigError at validation time.
Source
Thrown at server/consumer.go:793
}
}
if config.AckWait < 0 {
return NewJSConsumerAckWaitNegativeError()
}
// Ack Flow Control policy requires push-based flow-controlled consumer.
if config.AckPolicy == AckFlowControl {
if config.DeliverSubject == _EMPTY_ {
return NewJSConsumerAckFCRequiresPushError()
}
if !config.FlowControl {
return NewJSConsumerAckFCRequiresFCError()
}
// We currently limit using heartbeat of 1s, since those are used for ephemeral sourcing consumers as well.
// We could decide to relax this in the future, but need to be careful to not allow a heartbeat larger
// than the stalled source timeout.
if config.Heartbeat != sourceHealthHB {
return NewJSStreamInvalidConfigError(fmt.Errorf("flow control ack policy heartbeat needs to be 1s"))
}
if config.MaxAckPending <= 0 {
return NewJSConsumerAckFCRequiresMaxAckPendingError()
}
if config.AckWait != 0 || len(config.BackOff) > 0 {
return NewJSConsumerAckFCRequiresNoAckWaitError()
}
if config.MaxDeliver > 0 {
return NewJSConsumerAckFCRequiresNoMaxDeliverError()
}
}
// Check if we have a BackOff defined that MaxDeliver is within range etc.
if lbo := len(config.BackOff); lbo > 0 && config.MaxDeliver != -1 && lbo > config.MaxDeliver {
return NewJSConsumerMaxDeliverBackoffError()
}
if len(config.Description) > JSMaxDescriptionLen {View on GitHub (pinned to 3a66a489d2)
Solutions
- Set Heartbeat (client-side IdleHeartbeat) to exactly 1s (time.Second / "1s" in JSON config).
- If a different heartbeat is required, switch AckPolicy off the flow-control policy (e.g. explicit/all) so this constraint no longer applies.
- Also satisfy the companion constraints checked nearby: MaxAckPending > 0 and AckWait == 0 with empty BackOff.
Example fix
// before
cc := &nats.ConsumerConfig{AckPolicy: nats.AckFCPolicy, Heartbeat: 2 * time.Second}
// after
cc := &nats.ConsumerConfig{AckPolicy: nats.AckFCPolicy, Heartbeat: time.Second} Defensive patterns
Strategy: validation
Validate before calling
if cc.AckPolicy == nats.AckFCPolicy && cc.Heartbeat != time.Second {
return fmt.Errorf("flow control ack policy requires Heartbeat == 1s, got %v", cc.Heartbeat)
}
if cc.AckPolicy == nats.AckFCPolicy && cc.MaxAckPending <= 0 {
return fmt.Errorf("flow control ack policy requires MaxAckPending > 0")
} Type guard
func fcAckConfigValid(hb time.Duration, maxAckPending int) bool {
return hb == time.Second && maxAckPending > 0
} Try / catch
_, err := js.AddConsumer(stream, cc)
var cerr *nats.APIError
if errors.As(err, &cerr) && strings.Contains(cerr.Description, "heartbeat needs to be 1s") {
cc.Heartbeat = time.Second
return js.AddConsumer(stream, cc)
} Prevention
- Always pair AckFCPolicy with IdleHeartbeat: time.Second
- Remember AckWait must be 0 and BackOff empty when using flow control acks
- Prefer explicit/all ack policies if you need custom heartbeat intervals
When it happens
Trigger: Creating/updating a consumer with AckPolicy set to the flow-control ack policy and Heartbeat set to anything other than 1s (e.g. 2s, 500ms, or via the client library's Heartbeat/IdleHeartbeat field).
Common situations: Tuning heartbeats for slower networks and picking 2-5s while also enabling flow control acks; copying sourcing consumer examples that omit Heartbeat (zero is also != 1s).
Related errors
- got corrupted escaped character
- max_ack_pending must be set to -1
- max_batch must not be negative
- max_expires must not be negative
- max_bytes must not be negative
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/d131a636883554f1.
Report an issue: GitHub.