nats-io/nats-server · error · JSConsumerInvalidPolicyError
consumer delivery policy is deliver %s, but optional %s is n
Error message
consumer delivery policy is deliver %s, but optional %s is not set
What it means
The inverse of the previous conflict: the chosen DeliverPolicy requires an optional start value that was not provided. The notSet helper returns this error naming the policy and the missing option — e.g. DeliverByStartSequence with OptStartSeq == 0, or DeliverByStartTime with a zero OptStartTime.
Source
Thrown at server/consumer.go:921
// Check subject filters do not overlap.
for outer, subject := range subjectFilters {
if !IsValidSubject(subject) {
return NewJSStreamInvalidConfigError(ErrBadSubject)
}
for inner, ssubject := range subjectFilters {
if inner != outer && subjectIsSubsetMatch(subject, ssubject) {
return NewJSConsumerOverlappingSubjectFiltersError()
}
}
}
// Helper function to formulate similar errors.
badStart := func(dp, start string) error {
return fmt.Errorf("consumer delivery policy is deliver %s, but optional start %s is also set", dp, start)
}
notSet := func(dp, notSet string) error {
return fmt.Errorf("consumer delivery policy is deliver %s, but optional %s is not set", dp, notSet)
}
// Check on start position conflicts.
switch config.DeliverPolicy {
case DeliverAll:
if config.OptStartSeq > 0 {
return NewJSConsumerInvalidPolicyError(badStart("all", "sequence"))
}
if config.OptStartTime != nil {
return NewJSConsumerInvalidPolicyError(badStart("all", "time"))
}
case DeliverLast:
if config.OptStartSeq > 0 {
return NewJSConsumerInvalidPolicyError(badStart("last", "sequence"))
}
if config.OptStartTime != nil {
return NewJSConsumerInvalidPolicyError(badStart("last", "time"))
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Supply the matching value: set OptStartSeq to the desired sequence when using DeliverByStartSequence, or OptStartTime when using DeliverByStartTime.
- If you actually want everything, switch DeliverPolicy to DeliverAll instead of by-sequence/time.
- Validate the consumer config client-side before submitting to catch the missing pairing early.
Example fix
// before
cc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverByStartSequence}
// after
cc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverByStartSequence, OptStartSeq: 1000} Defensive patterns
Strategy: validation
Validate before calling
func requiresStart(cc *nats.ConsumerConfig) error {
switch cc.DeliverPolicy {
case nats.DeliverByStartSequence:
if cc.OptStartSeq == 0 {
return fmt.Errorf("DeliverByStartSequence requires OptStartSeq")
}
case nats.DeliverByStartTime:
if cc.OptStartTime.IsZero() {
return fmt.Errorf("DeliverByStartTime requires OptStartTime")
}
}
return nil
} Try / catch
_, err := js.AddConsumer(stream, cc)
if err != nil && strings.Contains(err.Error(), "is not set") {
cc.DeliverPolicy = nats.DeliverAll // safe fallback
return js.AddConsumer(stream, cc)
} Prevention
- Whenever you set DeliverByStartSequence/DeliverByStartTime, set the matching OptStartSeq/OptStartTime in the same place
- Default to DeliverAll when no specific replay point is needed
- Validate consumer config client-side before submitting
When it happens
Trigger: ConsumerConfig with DeliverPolicy: DeliverByStartSequence but OptStartSeq left at 0; DeliverPolicy: DeliverByStartTime but OptStartTime unset (zero time).
Common situations: Setting only the deliver policy enum from CLI flags/UI and forgetting the matching start value; JSON payloads missing the optional field; defaults not filled in by an older client library.
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/9a0f940735454266.
Report an issue: GitHub.