nats-io/nats-server · error

subject filter '%s' for the mirror %w

Error message

subject filter '%s' for the mirror %w

What it means

During stream creation/update, a mirror's FilterSubject is validated with IsValidSubject; this error wraps ErrBadSubject when the filter is non-empty and not a valid NATS subject. The stream is not created.

Source

Thrown at server/stream.go:939

		jsa.mu.Unlock()
		js.mu.RLock()
		if isClustered {
			_, reserved = js.tieredStreamAndReservationCount(a.Name, tier, cfg)
		}
		if err := js.checkAllLimits(&selected, tier, cfg, reserved, 0); err != nil {
			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)
					}
				}
			}
		}
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Correct the mirror FilterSubject to a valid NATS subject (token rules, wildcards only as full tokens: *, >).
  2. If you want the whole mirror, remove FilterSubject (set it empty) instead of an invalid value.
  3. Validate with server.IsValidSubject or a subject-validation helper before calling AddStream.

Example fix

// before
Mirror: &StreamSource{Name: "ORDERS", FilterSubject: "orders..new"}
// after
Mirror: &StreamSource{Name: "ORDERS", FilterSubject: "orders.>"}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Mirror != nil && cfg.Mirror.FilterSubject != "" && !nats.IsValidSubject(cfg.Mirror.FilterSubject) {
  return fmt.Errorf("bad mirror filter subject: %q", cfg.Mirror.FilterSubject)
}

Try / catch

cfg, err := js.AddStream(streamCfg)
if err != nil {
  var apiErr *nats.APIError
  if errors.As(err, &apiErr) && errors.Is(err, nats.ErrBadSubject) { /* fix subject and retry once */ }
}

Prevention

When it happens

Trigger: Calling AddStream/UpdateStream with cfg.Mirror.FilterSubject containing wildcards in the wrong place, adjacent tokens (foo..bar), leading/trailing dots, spaces, or other invalid characters.

Common situations: Mirroring a subset of a remote stream and typing an invalid filter (e.g. "foo.>.*" misuse or "foo bar"), or building the filter from unvalidated user input.

Related errors


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