nats-io/nats-server · error

unable to get subject transform for source: %v

Error message

unable to get subject transform for source: %v

What it means

While (re)building the internal source state for a stream's mirror/sources, JetStream creates a SubjectTransform for each source's Source/Destination pair via NewSubjectTransform; if construction fails, the stream update/create is aborted with this error. It indicates one of the configured source subject transforms is invalid.

Source

Thrown at server/stream.go:2799

					mset.cfg.Sources = append(mset.cfg.Sources, s)
					mset.cfgMu.Unlock()

					var si *sourceInfo

					if len(s.SubjectTransforms) == 0 {
						si = &sourceInfo{name: s.Name, iname: s.iname, sf: s.FilterSubject}
					} else {
						si = &sourceInfo{name: s.Name, iname: s.iname}
						si.trs = make([]*subjectTransform, len(s.SubjectTransforms))
						si.sfs = make([]string, len(s.SubjectTransforms))
						for i := range s.SubjectTransforms {
							// err can be ignored as already validated in config check
							si.sfs[i] = s.SubjectTransforms[i].Source
							var err error
							si.trs[i], err = NewSubjectTransform(s.SubjectTransforms[i].Source, s.SubjectTransforms[i].Destination)
							if err != nil {
								mset.mu.Unlock()
								return fmt.Errorf("unable to get subject transform for source: %v", err)
							}
						}
					}

					mset.sources[s.iname] = si
					if needsStartingSeqNum == nil {
						needsStartingSeqNum = make(map[string]struct{})
					}
					needsStartingSeqNum[s.iname] = struct{}{}
				} else {
					// source already exists
					delete(currentIName, s.iname)
				}

				// Remove the source if it still exists, but only if not using a pre-existing consumer.
				if s.Consumer == nil {
					delete(currentConsumers, getSourcingConsumerIName(s, cfg.Sources))
				}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Validate each Sources[i].SubjectTransform subject strings with nats.SubjectTransformPre or by testing NewSubjectTransform client-side logic (valid subject syntax).
  2. Fix or remove the offending Source/Destination pair in the stream config and retry UpdateStream.
  3. Check the wrapped error (%v) to see which transform rule was rejected.

Example fix

// before
Sources: []StreamSource{{Name: "OTHER", SubjectTransform: &SubjectTransformConfig{Source: "foo..bar"}}}
// after
Sources: []StreamSource{{Name: "OTHER", SubjectTransform: &SubjectTransformConfig{Source: "foo.*", Destination: "baz.*"}}}
Defensive patterns

Strategy: validation

Validate before calling

for _, s := range cfg.Sources {
    if t := s.SubjectTransform; t != nil {
        if err := validTransformPair(t.Source, t.Destination); err != nil { return err }
    }
}

Try / catch

if err != nil && strings.HasPrefix(err.Error(), "unable to get subject transform for source") { /* fix Sources[i].SubjectTransform */ }

Prevention

When it happens

Trigger: StreamConfig.Sources[i].SubjectTransform (Source/Destination) that NewSubjectTransform cannot compile, e.g. invalid wildcard or malformed subject in a source's transform, added during UpdateStream.

Common situations: Typo in transform source like 'foo.>' vs 'foo.*' misuse, empty Destination, or invalid subject characters in a mirrored-source transform.

Related errors


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