nats-io/nats-server · error

stream configuration for subject transform from '%s' to '%s'

Error message

stream configuration for subject transform from '%s' to '%s': %w

What it means

When a subject transform is being added to a stream for the first time (ocfg.SubjectTransform==nil, cfg.SubjectTransform!=nil), JetStream compiles it with NewSubjectTransform and wraps any failure as "stream configuration for subject transform from '%s' to '%s'". The transform cannot be created because the Source/Destination subjects are invalid.

Source

Thrown at server/stream.go:2875

			cfg.RePublish.Destination = fwcs
		}
		tr, err := NewSubjectTransform(cfg.RePublish.Source, cfg.RePublish.Destination)
		if err != nil {
			mset.mu.Unlock()
			return fmt.Errorf("stream configuration for republish from '%s' to '%s': %w", cfg.RePublish.Source, cfg.RePublish.Destination, err)
		}
		// Assign our transform for republishing.
		mset.tr = tr
	} else {
		mset.tr = nil
	}

	// Check for changes to subject transform
	if ocfg.SubjectTransform == nil && cfg.SubjectTransform != nil {
		tr, err := NewSubjectTransform(cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination)
		if err != nil {
			mset.mu.Unlock()
			return fmt.Errorf("stream configuration for subject transform from '%s' to '%s': %w", cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination, err)
		}
		mset.itr = tr
	} else if ocfg.SubjectTransform != nil && cfg.SubjectTransform != nil &&
		(ocfg.SubjectTransform.Source != cfg.SubjectTransform.Source || ocfg.SubjectTransform.Destination != cfg.SubjectTransform.Destination) {
		tr, err := NewSubjectTransform(cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination)
		if err != nil {
			mset.mu.Unlock()
			return fmt.Errorf("stream configuration for subject transform from '%s' to '%s': %w", cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination, err)
		}
		mset.itr = tr
	} else if ocfg.SubjectTransform != nil && cfg.SubjectTransform == nil {
		mset.itr = nil
	}

	js := mset.js

	if targetTier := tierName(cfg.Replicas); mset.tier != targetTier {
		// In cases such as R1->R3, only one update is needed

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Match wildcard token counts between Source and Destination.
  2. Validate both subjects for syntax before calling UpdateStream.
  3. Inspect the wrapped inner error for the exact rule that failed.

Example fix

// before
SubjectTransform: &SubjectTransformConfig{Source: "orders..new", Destination: "orders.new"}
// after
SubjectTransform: &SubjectTransformConfig{Source: "orders.*", Destination: "orders.new.*"}
Defensive patterns

Strategy: validation

Validate before calling

if st := cfg.SubjectTransform; st != nil {
    if err := validTransformPair(st.Source, st.Destination); err != nil { return err }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "subject transform from") { /* fix SubjectTransform config */ }

Prevention

When it happens

Trigger: UpdateStream adding StreamConfig.SubjectTransform with a malformed Source or Destination (invalid wildcard usage, mismatched token counts, illegal characters).

Common situations: First-time introduction of a transform where Source 'orders.*' is mapped to a Destination with a different wildcard count, or copy-paste of subjects containing trailing dots/spaces.

Related errors


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