{"record":{"id":"cfc5830b9a58ab64","repo":"nats-io/nats-server","slug":"subject-filter-s-for-the-mirror-w","errorCode":null,"errorMessage":"subject filter '%s' for the mirror %w","messagePattern":"subject filter '(.+?)' for the mirror %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":939,"sourceCode":"\t\tjsa.mu.Unlock()\n\t\tjs.mu.RLock()\n\t\tif isClustered {\n\t\t\t_, reserved = js.tieredStreamAndReservationCount(a.Name, tier, cfg)\n\t\t}\n\t\tif err := js.checkAllLimits(&selected, tier, cfg, reserved, 0); err != nil {\n\t\t\tjs.mu.RUnlock()\n\t\t\treturn nil, err\n\t\t}\n\t\tjs.mu.RUnlock()\n\t\tjsa.mu.Lock()\n\t}\n\n\t// If mirror, check if the transforms (if any) are valid.\n\tif cfg.Mirror != nil {\n\t\tif len(cfg.Mirror.SubjectTransforms) == 0 {\n\t\t\tif cfg.Mirror.FilterSubject != _EMPTY_ && !IsValidSubject(cfg.Mirror.FilterSubject) {\n\t\t\t\tjsa.mu.Unlock()\n\t\t\t\treturn nil, fmt.Errorf(\"subject filter '%s' for the mirror %w\", cfg.Mirror.FilterSubject, ErrBadSubject)\n\t\t\t}\n\t\t} else {\n\t\t\tfor _, st := range cfg.Mirror.SubjectTransforms {\n\t\t\t\tif st.Source != _EMPTY_ && !IsValidSubject(st.Source) {\n\t\t\t\t\tjsa.mu.Unlock()\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid subject transform source '%s' for the mirror: %w\", st.Source, ErrBadSubject)\n\t\t\t\t}\n\t\t\t\t// check the transform, if any, is valid\n\t\t\t\tif st.Destination != _EMPTY_ {\n\t\t\t\t\tif _, err = NewSubjectTransform(st.Source, st.Destination); err != nil {\n\t\t\t\t\t\tjsa.mu.Unlock()\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"subject transform from '%s' to '%s' for the mirror: %w\", st.Source, st.Destination, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L921-L957","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Correct the mirror FilterSubject to a valid NATS subject (token rules, wildcards only as full tokens: *, >).","If you want the whole mirror, remove FilterSubject (set it empty) instead of an invalid value.","Validate with server.IsValidSubject or a subject-validation helper before calling AddStream."],"exampleFix":"// before\nMirror: &StreamSource{Name: \"ORDERS\", FilterSubject: \"orders..new\"}\n// after\nMirror: &StreamSource{Name: \"ORDERS\", FilterSubject: \"orders.>\"}","handlingStrategy":"validation","validationCode":"if cfg.Mirror != nil && cfg.Mirror.FilterSubject != \"\" && !nats.IsValidSubject(cfg.Mirror.FilterSubject) {\n  return fmt.Errorf(\"bad mirror filter subject: %q\", cfg.Mirror.FilterSubject)\n}","typeGuard":null,"tryCatchPattern":"cfg, err := js.AddStream(streamCfg)\nif err != nil {\n  var apiErr *nats.APIError\n  if errors.As(err, &apiErr) && errors.Is(err, nats.ErrBadSubject) { /* fix subject and retry once */ }\n}","preventionTips":["Validate all subjects with IsValidSubject before config submission.","Avoid empty tokens and misplaced wildcards.","Load test configs through the same validation the server applies."],"tags":["jetstream","mirror","subject","validation"],"backgroundTag":"invalid-nats-subject","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}