{"record":{"id":"e7c6efdc6ad4d35a","repo":"nats-io/nats-server","slug":"consumer-delivery-policy-is-deliver-s-but-option","errorCode":null,"errorMessage":"consumer delivery policy is deliver %s, but optional start %s is also set","messagePattern":"consumer delivery policy is deliver (.+?), but optional start (.+?) is also set","errorType":"validation","errorClass":"JSConsumerInvalidPolicyError","httpStatus":null,"severity":"error","filePath":"server/consumer.go","lineNumber":918,"sourceCode":"\t\t}\n\t}\n\tsubjectFilters := gatherSubjectFilters(config.FilterSubject, config.FilterSubjects)\n\n\t// Check subject filters do not overlap.\n\tfor outer, subject := range subjectFilters {\n\t\tif !IsValidSubject(subject) {\n\t\t\treturn NewJSStreamInvalidConfigError(ErrBadSubject)\n\t\t}\n\t\tfor inner, ssubject := range subjectFilters {\n\t\t\tif inner != outer && subjectIsSubsetMatch(subject, ssubject) {\n\t\t\t\treturn NewJSConsumerOverlappingSubjectFiltersError()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Helper function to formulate similar errors.\n\tbadStart := func(dp, start string) error {\n\t\treturn fmt.Errorf(\"consumer delivery policy is deliver %s, but optional start %s is also set\", dp, start)\n\t}\n\tnotSet := func(dp, notSet string) error {\n\t\treturn fmt.Errorf(\"consumer delivery policy is deliver %s, but optional %s is not set\", dp, notSet)\n\t}\n\n\t// Check on start position conflicts.\n\tswitch config.DeliverPolicy {\n\tcase DeliverAll:\n\t\tif config.OptStartSeq > 0 {\n\t\t\treturn NewJSConsumerInvalidPolicyError(badStart(\"all\", \"sequence\"))\n\t\t}\n\t\tif config.OptStartTime != nil {\n\t\t\treturn NewJSConsumerInvalidPolicyError(badStart(\"all\", \"time\"))\n\t\t}\n\tcase DeliverLast:\n\t\tif config.OptStartSeq > 0 {\n\t\t\treturn NewJSConsumerInvalidPolicyError(badStart(\"last\", \"sequence\"))\n\t\t}","sourceCodeStart":900,"sourceCodeEnd":936,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/consumer.go#L900-L936","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverAll, OptStartSeq: 42}\n// after\ncc := nats.ConsumerConfig{DeliverPolicy: nats.DeliverByStartSequence, OptStartSeq: 42}","handlingStrategy":"validation","validationCode":"func startConflict(cc *nats.ConsumerConfig) error {\n    switch cc.DeliverPolicy {\n    case nats.DeliverAll, nats.DeliverLast, nats.DeliverNew, nats.DeliverLastPerSubject:\n        if cc.OptStartSeq > 0 || !cc.OptStartTime.IsZero() {\n            return fmt.Errorf(\"deliver policy %v conflicts with explicit start\", cc.DeliverPolicy)\n        }\n    case nats.DeliverByStartSequence:\n        if !cc.OptStartTime.IsZero() {\n            return fmt.Errorf(\"start-seq policy conflicts with OptStartTime\")\n        }\n    case nats.DeliverByStartTime:\n        if cc.OptStartSeq > 0 {\n            return fmt.Errorf(\"start-time policy conflicts with OptStartSeq\")\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"_, err := js.AddConsumer(stream, cc)\nif err != nil && strings.Contains(err.Error(), \"is also set\") {\n    cc.OptStartSeq, cc.OptStartTime = 0, time.Time{} // strip conflicting starts\n    return js.AddConsumer(stream, cc)\n}","preventionTips":["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"],"tags":["jetstream","consumer-config","validation"],"backgroundTag":"invalid-consumer-config","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}