nats-io/nats-server · error

storage type can not be updated

Error message

storage type can not be updated

What it means

A consumer update tried to change MemoryStorage, i.e. switch the consumer between memory and file storage. Storage type is fixed at creation, so checkNewConsumerConfig rejects any difference. The request fails with this error.

Source

Thrown at server/consumer.go:2538

		} else {
			burst = int(acc.srv.getOpts().MaxPayload)
		}
	}

	o.rlimit = rate.NewLimiter(rl, burst)
}

// Check if new consumer config allowed vs old.
func (acc *Account) checkNewConsumerConfig(cfg, ncfg *ConsumerConfig) error {
	if reflect.DeepEqual(cfg, ncfg) {
		return nil
	}
	// Something different, so check since we only allow certain things to be updated.
	if cfg.DeliverPolicy != ncfg.DeliverPolicy {
		return errors.New("deliver policy can not be updated")
	}
	if cfg.MemoryStorage != ncfg.MemoryStorage {
		return errors.New("storage type can not be updated")
	}
	// Direct and Sourcing classify the consumer for its whole lifetime, which the
	// stream relies on when walking its consumer list, so they can not change.
	if cfg.Direct != ncfg.Direct {
		return errors.New("direct can not be updated")
	}
	if cfg.Sourcing != ncfg.Sourcing {
		return errors.New("sourcing can not be updated")
	}
	if cfg.OptStartSeq != ncfg.OptStartSeq {
		return errors.New("start sequence can not be updated")
	}
	if cfg.OptStartTime != nil && ncfg.OptStartTime != nil {
		// Both have start times set, compare them directly:
		if !cfg.OptStartTime.Equal(*ncfg.OptStartTime) {
			return errors.New("start time can not be updated")
		}
	} else if cfg.OptStartTime != nil || ncfg.OptStartTime != nil {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Delete and recreate the consumer with the desired storage type.
  2. Keep the existing storage type in the update payload.
  3. Use a new durable name with the desired storage and cut over.
  4. Standardize storage settings in templates so env-specific diffs don't flip this field.

Example fix

// before
js.UpdateConsumer(stream, &nats.ConsumerConfig{Durable: "worker", MemoryStorage: true})
// after
js.DeleteConsumer(stream, "worker")
js.AddConsumer(stream, &nats.ConsumerConfig{Durable: "worker", MemoryStorage: true})
Defensive patterns

Strategy: validation

Validate before calling

if existing.MemoryStorage != desired.MemoryStorage {
	return errors.New("storage type cannot be updated; recreate the consumer")
}

Prevention

When it happens

Trigger: js.UpdateConsumer (or CONSUMER.CREATE on an existing durable) where cfg.MemoryStorage differs from ncfg.MemoryStorage — e.g. created with FileStorage but update passes MemoryStorage: true (or vice versa).

Common situations: Switching consumers to memory for performance after rollout; environment-specific templates toggling storage; recreating a durable from an infra-as-code diff that changed the storage flag.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/ef776b2407574f08. Report an issue: GitHub.