{"record":{"id":"5d06debc06e1c9cf","repo":"nats-io/nats-server","slug":"deliver-policy-can-not-be-updated","errorCode":null,"errorMessage":"deliver policy can not be updated","messagePattern":"deliver policy can not be updated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/consumer.go","lineNumber":2535,"sourceCode":"\t\tacc.mu.RUnlock()\n\t\tif mpay > 0 {\n\t\t\tburst = int(mpay)\n\t\t} else {\n\t\t\tburst = int(acc.srv.getOpts().MaxPayload)\n\t\t}\n\t}\n\n\to.rlimit = rate.NewLimiter(rl, burst)\n}\n\n// Check if new consumer config allowed vs old.\nfunc (acc *Account) checkNewConsumerConfig(cfg, ncfg *ConsumerConfig) error {\n\tif reflect.DeepEqual(cfg, ncfg) {\n\t\treturn nil\n\t}\n\t// Something different, so check since we only allow certain things to be updated.\n\tif cfg.DeliverPolicy != ncfg.DeliverPolicy {\n\t\treturn errors.New(\"deliver policy can not be updated\")\n\t}\n\tif cfg.MemoryStorage != ncfg.MemoryStorage {\n\t\treturn errors.New(\"storage type can not be updated\")\n\t}\n\t// Direct and Sourcing classify the consumer for its whole lifetime, which the\n\t// stream relies on when walking its consumer list, so they can not change.\n\tif cfg.Direct != ncfg.Direct {\n\t\treturn errors.New(\"direct can not be updated\")\n\t}\n\tif cfg.Sourcing != ncfg.Sourcing {\n\t\treturn errors.New(\"sourcing can not be updated\")\n\t}\n\tif cfg.OptStartSeq != ncfg.OptStartSeq {\n\t\treturn errors.New(\"start sequence can not be updated\")\n\t}\n\tif cfg.OptStartTime != nil && ncfg.OptStartTime != nil {\n\t\t// Both have start times set, compare them directly:\n\t\tif !cfg.OptStartTime.Equal(*ncfg.OptStartTime) {","sourceCodeStart":2517,"sourceCodeEnd":2553,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/consumer.go#L2517-L2553","documentation":"checkNewConsumerConfig compares the existing consumer config with the proposed update and rejects changes to immutable fields. DeliverPolicy (DeliverAll, DeliverLast, DeliverByStartSequence, DeliverByStartTime, etc.) cannot change after a durable consumer is created because it determines where the consumer begins consuming. The update request fails with this error.","triggerScenarios":"Calling js.UpdateConsumer or the $JS.API.CONSUMER.CREATE API with an existing durable name but a different DeliverPolicy than the stored config.","commonSituations":"Changing an app from DeliverLast to DeliverNew during redeployment; reusing an old durable name with different start semantics after a refactor; CI applying config drift from a template with a different deliver policy.","solutions":["Delete the consumer (js.DeleteConsumer / $JS.API.CONSUMER.DELETE) and recreate it with the desired DeliverPolicy.","Use a new durable name for the new policy and migrate consumers to it.","Revert the config change so DeliverPolicy matches the existing consumer.","Read the existing config first (js.ConsumerInfo) and only send fields you intend to change."],"exampleFix":"// before\njs.UpdateConsumer(stream, &nats.ConsumerConfig{Durable: \"worker\", DeliverPolicy: nats.DeliverLast})\n// after\njs.DeleteConsumer(stream, \"worker\")\njs.AddConsumer(stream, &nats.ConsumerConfig{Durable: \"worker\", DeliverPolicy: nats.DeliverLast})","handlingStrategy":"validation","validationCode":"func safeUpdate(existing, desired *nats.ConsumerConfig) (*nats.ConsumerConfig, error) {\n\tif existing.DeliverPolicy != desired.DeliverPolicy {\n\t\treturn nil, fmt.Errorf(\"deliver policy cannot be updated; delete and recreate consumer %q\", existing.Durable)\n\t}\n\treturn desired, nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch ConsumerInfo and diff before updating","Treat DeliverPolicy as create-only in infrastructure code","On intentional policy change, delete + recreate via automation"],"tags":["jetstream","consumer","immutable-config","update"],"backgroundTag":"jetstream-consumer-field-immutable","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}