nats-io/nats-server · error · ApiError (JSMirrorInvalidSubjectFilter)

10151

10151

Error message

%w %s

What it means

A mirror's SubjectTransforms entry contains an invalid source subject (or a source/destination mapping that fails ValidateMapping). The server wraps ErrBadSubject with the offending subject and returns JSMirrorInvalidSubjectFilterError (10151) via JSStreamInvalidConfigError during mirror config validation.

Source

Thrown at server/stream.go:2138

				return StreamConfig{}, NewJSMirrorDurableConsumerCfgInvalidError()
			}
			if cfg.Mirror.FilterSubject != _EMPTY_ {
				return StreamConfig{}, NewJSMirrorDurableConsumerCfgInvalidError()
			}
		}
		if cfg.Mirror.FilterSubject != _EMPTY_ && len(cfg.Mirror.SubjectTransforms) != 0 {
			return StreamConfig{}, NewJSMirrorMultipleFiltersNotAllowedError()
		}
		if cfg.SubjectDeleteMarkerTTL > 0 {
			// Delete markers cannot be configured on a mirror as it would result in new
			// tombstones which would use up sequence numbers, diverging from the origin
			// stream.
			return StreamConfig{}, NewJSStreamInvalidConfigError(fmt.Errorf("subject delete markers forbidden on mirrors"))
		}
		// Check subject filters overlap.
		for outer, tr := range cfg.Mirror.SubjectTransforms {
			if tr.Source != _EMPTY_ && !IsValidSubject(tr.Source) {
				return StreamConfig{}, NewJSMirrorInvalidSubjectFilterError(fmt.Errorf("%w %s", ErrBadSubject, tr.Source))
			}

			err := ValidateMapping(tr.Source, tr.Destination)
			if err != nil {
				return StreamConfig{}, NewJSMirrorInvalidTransformDestinationError(err)
			}

			for inner, innertr := range cfg.Mirror.SubjectTransforms {
				if inner != outer && SubjectsCollide(tr.Source, innertr.Source) {
					return StreamConfig{}, NewJSMirrorOverlappingSubjectFiltersError()
				}
			}
		}
		// Do not perform checks if External is provided, as it could lead to
		// checking against itself (if sourced stream name is the same on different JetStream)
		if cfg.Mirror.External == nil {
			if !isValidAssetName(cfg.Mirror.Name) {
				return StreamConfig{}, NewJSMirrorInvalidStreamNameError()

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Fix the SubjectTransforms source subject to a valid NATS subject (no spaces, valid tokens/wildcards)
  2. Ensure each transform has both a valid non-empty Source and Destination
  3. Validate subjects with server IsValidSubject semantics (tokens separated by '.', legal wildcard use) before submitting

Example fix

// before
tf := SubjectTransformConfig{Source: "foo..bar", Destination: "baz"}
// after
tf := SubjectTransformConfig{Source: "foo.bar", Destination: "baz"}
Defensive patterns

Strategy: validation

Validate before calling

for _, tr := range cfg.Mirror.SubjectTransforms {
    if tr.Source != "" && !subjectIsValid(tr.Source) {
        return fmt.Errorf("invalid mirror transform source: %q", tr.Source)
    }
    if err := validateMapping(tr.Source, tr.Destination); err != nil {
        return err
    }
}

Try / catch

var ec *jsapi.APIError
if errors.As(err, &ec) && ec.ErrorCode == 10151 {
    // inspect Subjects transforms, fix invalid source, resubmit
}

Prevention

When it happens

Trigger: AddStream/UpdateStream with Mirror.SubjectTransforms where tr.Source is non-empty and !IsValidSubject(tr.Source) — e.g. empty destination, trailing dot, invalid wildcard placement, or spaces in the subject.

Common situations: Typos in transform subjects like 'foo..bar' or 'foo bar'; constructing transforms programmatically with empty/invalid source strings; configs hand-edited with wildcards in illegal positions.

Related errors


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