{"record":{"id":"dc66df3b4da9714c","repo":"nats-io/nats-server","slug":"start-time-can-not-be-updated","errorCode":null,"errorMessage":"start time can not be updated","messagePattern":"start time can not be updated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/consumer.go","lineNumber":2554,"sourceCode":"\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) {\n\t\t\treturn errors.New(\"start time can not be updated\")\n\t\t}\n\t} else if cfg.OptStartTime != nil || ncfg.OptStartTime != nil {\n\t\t// At least one start time is set and the other is not\n\t\treturn errors.New(\"start time can not be updated\")\n\t}\n\tif cfg.AckPolicy != ncfg.AckPolicy {\n\t\treturn errors.New(\"ack policy can not be updated\")\n\t}\n\tif cfg.ReplayPolicy != ncfg.ReplayPolicy {\n\t\treturn errors.New(\"replay policy can not be updated\")\n\t}\n\tif cfg.Heartbeat != ncfg.Heartbeat {\n\t\treturn errors.New(\"heart beats can not be updated\")\n\t}\n\tif cfg.FlowControl != ncfg.FlowControl {\n\t\treturn errors.New(\"flow control can not be updated\")\n\t}\n","sourceCodeStart":2536,"sourceCodeEnd":2572,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/consumer.go#L2536-L2572","documentation":"When both the existing and the proposed configs have OptStartTime set but the times differ, the start time is considered changed and rejected — OptStartTime cannot be updated after creation. checkNewConsumerConfig compares them with time.Equal and returns this error on mismatch.","triggerScenarios":"js.UpdateConsumer on an existing durable created with DeliverByStartTime where the update passes a different OptStartTime timestamp (even a slightly different value for the same intended moment).","commonSituations":"Replaying from 'yesterday' instead of the original start date; regenerating configs from templates where the computed timestamp shifts each run; timezone or precision differences (RFC3339 with/without fractional seconds) causing inequality.","solutions":["Delete and recreate the consumer with the desired OptStartTime.","Keep OptStartTime identical (same instant) in update requests.","Freeze the start-time value in config management instead of computing it at deploy time.","Normalize timestamps (UTC, consistent precision) before comparing/sending."],"exampleFix":"// before\njs.UpdateConsumer(stream, &nats.ConsumerConfig{Durable: \"replay\", OptStartTime: &newTime})\n// after\njs.DeleteConsumer(stream, \"replay\")\njs.AddConsumer(stream, &nats.ConsumerConfig{Durable: \"replay\", OptStartTime: &newTime})","handlingStrategy":"validation","validationCode":"if existing.OptStartTime != nil && desired.OptStartTime != nil && !existing.OptStartTime.Equal(*desired.OptStartTime) {\n\treturn errors.New(\"start time cannot be updated; recreate the consumer\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store the original start time and reuse it verbatim in updates","Normalize timestamps to UTC with fixed precision","Compute time-based starts only at consumer creation"],"tags":["jetstream","consumer","start-time","immutable-config"],"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"}