nats-io/nats-server · error · ApiError
consumer durable name can not contain '.', '*', '>', '\', '/
Error message
consumer durable name can not contain '.', '*', '>', '\', '/'
What it means
The consumer's Durable field failed isValidAssetName because it contains '.', '*', '>', '\\' or '/'. Durable names become part of internal subjects and storage keys, so wildcard/path characters are forbidden. The server rejects the request with a JSStreamInvalidConfigError.
Source
Thrown at server/consumer.go:742
}
return nil
}
// Check the consumer config. If we are recovering don't check filter subjects.
func checkConsumerCfg(
config *ConsumerConfig,
srvLim *JSLimitOpts,
cfg *StreamConfig,
_ *Account,
accLim *JetStreamAccountLimits,
isRecovering bool,
) *ApiError {
if config.Name != _EMPTY_ && !isValidAssetName(config.Name) {
return NewJSStreamInvalidConfigError(errors.New("consumer name can not contain '.', '*', '>', '\\', '/'"))
}
if config.Durable != _EMPTY_ && !isValidAssetName(config.Durable) {
return NewJSStreamInvalidConfigError(errors.New("consumer durable name can not contain '.', '*', '>', '\\', '/'"))
}
// Check if replicas is defined but exceeds parent stream.
if config.Replicas > 0 && config.Replicas > cfg.Replicas {
return NewJSConsumerReplicasExceedsStreamError()
}
// Check that it is not negative
if config.Replicas < 0 {
return NewJSReplicasCountCannotBeNegativeError()
}
// If the stream is interest or workqueue retention make sure the replicas
// match that of the stream. This is REQUIRED for now.
if cfg.Retention == InterestPolicy || cfg.Retention == WorkQueuePolicy {
// Only error here if not recovering.
// We handle recovering in a different spot to allow consumer to come up
// if previous version allowed it to be created. We do not want it to not come up.
if !isRecovering && config.Replicas != 0 && config.Replicas != cfg.Replicas {
return NewJSConsumerReplicasShouldMatchStreamError()View on GitHub (pinned to 3a66a489d2)
Solutions
- Replace forbidden characters in the durable name with '-', '_' or alphanumerics.
- Add a sanitize/validate step before constructing ConsumerConfig.
- Let the server generate the durable name by omitting Durable when ephemeral behavior is acceptable.
- Keep durable names in one canonical format across services to avoid recurring validation failures.
Example fix
// before
cc := &nats.ConsumerConfig{Durable: "billing.worker.v2"}
// after
cc := &nats.ConsumerConfig{Durable: "billing-worker-v2"} Defensive patterns
Strategy: validation
Validate before calling
var invalidAssetNameRe = regexp.MustCompile(`[.*>\\/]`)
func validDurableName(durable string) bool {
return durable == "" || !invalidAssetNameRe.MatchString(durable)
}
if !validDurableName(cc.Durable) {
return fmt.Errorf("invalid durable name %q", cc.Durable)
} Prevention
- Standardize durable naming (alphanumerics, '-', '_') across services
- Validate durable names in CI config generation
- Do not reuse Kafka-style group IDs containing dots without sanitizing
When it happens
Trigger: Any consumer create/update call where config.Durable is non-empty and contains one of the forbidden characters: '.', '*', '>', '\\' or '/'.
Common situations: Using domain-like durable names such as 'my.app.worker'; reusing subscription subject strings as durable names; copy-pasting names from configs with slashes; clients from other ecosystems (e.g. Kafka group ids with dots) carried over.
Related errors
- consumer name can not contain '.', '*', '>', '\', '/'
- max_request_batch must be set if it's JetStream limits are s
- 10094
- deliver policy can not be updated
- storage type can not be updated
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/827b5665c9b81176.
Report an issue: GitHub.