nats-io/nats-server · error

invalid subject transform source '%s' for the mirror: %w

Error message

invalid subject transform source '%s' for the mirror: %w

What it means

Stream-creation validation (checkStreamCfgLocked path for mirrors): a Mirror.SubjectTransforms entry has a non-empty Source that failed IsValidSubject — the source subject contains invalid characters or wildcards ('>', '*', '.') used illegally for a mirror transform source. Wrapped with ErrBadSubject semantics.

Source

Thrown at server/stream.go:945

			js.mu.RUnlock()
			return nil, err
		}
		js.mu.RUnlock()
		jsa.mu.Lock()
	}

	// If mirror, check if the transforms (if any) are valid.
	if cfg.Mirror != nil {
		if len(cfg.Mirror.SubjectTransforms) == 0 {
			if cfg.Mirror.FilterSubject != _EMPTY_ && !IsValidSubject(cfg.Mirror.FilterSubject) {
				jsa.mu.Unlock()
				return nil, fmt.Errorf("subject filter '%s' for the mirror %w", cfg.Mirror.FilterSubject, ErrBadSubject)
			}
		} else {
			for _, st := range cfg.Mirror.SubjectTransforms {
				if st.Source != _EMPTY_ && !IsValidSubject(st.Source) {
					jsa.mu.Unlock()
					return nil, fmt.Errorf("invalid subject transform source '%s' for the mirror: %w", st.Source, ErrBadSubject)
				}
				// check the transform, if any, is valid
				if st.Destination != _EMPTY_ {
					if _, err = NewSubjectTransform(st.Source, st.Destination); err != nil {
						jsa.mu.Unlock()
						return nil, fmt.Errorf("subject transform from '%s' to '%s' for the mirror: %w", st.Source, st.Destination, err)
					}
				}
			}
		}
	}

	// Setup our internal indexed names here for sources and check if the transforms (if any) are valid.
	for _, ssi := range cfg.Sources {
		if len(ssi.SubjectTransforms) == 0 {
			// check the filter, if any, is valid
			if ssi.FilterSubject != _EMPTY_ && !IsValidSubject(ssi.FilterSubject) {
				jsa.mu.Unlock()

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Fix st.Source to a valid NATS subject.
  2. Remove the invalid transform entry if the source is not needed.
  3. Validate each transform source before constructing the config.

Example fix

// before
SubjectTransforms: []SubjectTransformConfig{{Source: "orders..in"}}
// after
SubjectTransforms: []SubjectTransformConfig{{Source: "orders.in"}}
Defensive patterns

Strategy: validation

Validate before calling

for _, st := range cfg.Mirror.SubjectTransforms {
  if st.Source != "" && !nats.IsValidSubject(st.Source) { return fmt.Errorf("bad transform source %q", st.Source) }
}

Try / catch

_, err := js.AddStream(cfg)
if err != nil && strings.Contains(err.Error(), "invalid subject transform source") { /* correct st.Source and resubmit */ }

Prevention

When it happens

Trigger: AddStream/UpdateStream with cfg.Mirror.SubjectTransforms containing an entry whose Source is malformed (empty tokens, bad wildcard placement, illegal characters).

Common situations: Typos in transform source subjects, generating transforms programmatically from invalid input, or copying filter-style wildcards that are illegal as transform sources.

Related errors


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