nats-io/nats-server · error · JSConsumerInvalidPolicyError
consumer delivery policy is deliver %s, but optional start %
Error message
consumer delivery policy is deliver %s, but optional start %s is also set
What it means
Consumer configuration validation detects a conflict between DeliverPolicy and an optional start position: the delivery policy already determines where to start (e.g. deliver all / last / new), but the user also supplied an explicit start (OptStartSeq or OptStartTime). The badStart helper formulates this error naming both the policy and the extra start option.
Source
Thrown at server/consumer.go:918
}
}
subjectFilters := gatherSubjectFilters(config.FilterSubject, config.FilterSubjects)
// 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"))
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove the redundant field: either clear OptStartSeq/OptStartTime or choose the corresponding DeliverPolicy (DeliverByStartSequence / DeliverByStartTime).
- Construct a fresh ConsumerConfig per request instead of mutating a shared struct.
- Validate config client-side (config.Validate() via the client library) before sending the consumer create/update API request.
Example fix
// before
cc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverAll, OptStartSeq: 42}
// after
cc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverByStartSequence, OptStartSeq: 42} Defensive patterns
Strategy: validation
Validate before calling
func startConflict(cc *nats.ConsumerConfig) error {
switch cc.DeliverPolicy {
case nats.DeliverAll, nats.DeliverLast, nats.DeliverNew, nats.DeliverLastPerSubject:
if cc.OptStartSeq > 0 || !cc.OptStartTime.IsZero() {
return fmt.Errorf("deliver policy %v conflicts with explicit start", cc.DeliverPolicy)
}
case nats.DeliverByStartSequence:
if !cc.OptStartTime.IsZero() {
return fmt.Errorf("start-seq policy conflicts with OptStartTime")
}
case nats.DeliverByStartTime:
if cc.OptStartSeq > 0 {
return fmt.Errorf("start-time policy conflicts with OptStartSeq")
}
}
return nil
} Try / catch
_, err := js.AddConsumer(stream, cc)
if err != nil && strings.Contains(err.Error(), "is also set") {
cc.OptStartSeq, cc.OptStartTime = 0, time.Time{} // strip conflicting starts
return js.AddConsumer(stream, cc)
} Prevention
- Build a fresh ConsumerConfig per request; never mutate shared structs
- Match each by-sequence/by-time policy with exactly one start field
- Run cc.Validate() client-side before calling the consumer API
When it happens
Trigger: ConsumerConfig with DeliverPolicy: DeliverAll/Last/New plus OptStartSeq > 0; DeliverPolicy: DeliverByStartSequence plus OptStartTime set; DeliverPolicy: DeliverByStartTime plus OptStartSeq set — checked in the start-position conflict switch at consumer.go:918.
Common situations: Reusing a partially filled ConsumerConfig struct across requests so a previous OptStartSeq/OptStartTime lingers; building config from JSON where both fields were present; library defaults populating one field while code sets another.
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/e7c6efdc6ad4d35a.
Report an issue: GitHub.