nats-io/nats-server · error · JSStreamInvalidConfigError
preferred server not permitted in placement
Error message
preferred server not permitted in placement
What it means
JetStream rejects a consumer or stream config whose Placement block sets a Preferred server. The library explicitly forbids preferred-server placement for consumers for now, treating it as an invalid config. This is a policy restriction in the server, not a transient failure.
Source
Thrown at server/consumer.go:1027
return NewJSConsumerEmptyGroupNameError()
}
if !validGroupName.MatchString(group) {
return NewJSConsumerInvalidGroupNameError()
}
}
} else {
// If PriorityPolicy is None or not set, reject if PriorityGroups or PinnedTTL are set
if len(config.PriorityGroups) > 0 {
return NewJSConsumerPriorityGroupWithPolicyNoneError()
}
if config.PinnedTTL > 0 {
return NewJSConsumerPinnedTTLWithoutPriorityPolicyNoneError()
}
}
// For now don't allow preferred server in placement.
if cfg.Placement != nil && cfg.Placement.Preferred != _EMPTY_ {
return NewJSStreamInvalidConfigError(fmt.Errorf("preferred server not permitted in placement"))
}
return nil
}
func (mset *stream) addConsumerWithAction(config *ConsumerConfig, action ConsumerAction, pedantic bool) (*consumer, error) {
return mset.addConsumerWithAssignment(config, _EMPTY_, nil, false, action, pedantic)
}
func (mset *stream) addConsumer(config *ConsumerConfig) (*consumer, error) {
return mset.addConsumerWithAction(config, ActionCreateOrUpdate, false)
}
func (mset *stream) addConsumerWithAssignment(config *ConsumerConfig, oname string, ca *consumerAssignment, isRecovering bool, action ConsumerAction, pedantic bool) (*consumer, error) {
return mset.addConsumerWithAssignmentAndMode(config, oname, ca, isRecovering, action, pedantic, false)
}
func (mset *stream) addConsumerForRestore(config *ConsumerConfig) (*consumer, error) {View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove the Preferred field from the consumer's Placement config
- If server targeting is required, drop Placement entirely and rely on cluster-wide consumer or use streams (where Preferred is allowed)
- Set Placement.Preferred to "" (empty string) while keeping other placement fields like Tags/Cluster
Example fix
// before
cfg.Placement = &Placement{Cluster: "east", Preferred: "nats-1"}
// after
cfg.Placement = &Placement{Cluster: "east"} Defensive patterns
Strategy: validation
Validate before calling
if cfg.Placement != nil && cfg.Placement.Preferred != "" {
return fmt.Errorf("consumer placement must not set Preferred server")
}
// then call js.AddConsumer(stream, cfg) Prevention
- Never reuse a stream Placement struct for consumer configs without clearing Preferred
- Keep a shared constructor that builds consumer placements with Preferred unset
- Add a unit test asserting consumer configs never carry Preferred
When it happens
Trigger: Calling AddConsumer (or creating/updating a consumer via js.AddConsumer or stream.AddConsumer with pedantic validation) with cfg.Placement != nil and cfg.Placement.Preferred set to a non-empty server name.
Common situations: Copying a stream's placement struct (which may legally carry Preferred) into a consumer config; migrating configs from tooling that assumed placement is fully shared between streams and consumers.
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/4ef618ed40a349b9.
Report an issue: GitHub.