{"record":{"id":"ee08da01588d48b9","repo":"nats-io/nats-server","slug":"subject-filter-s-for-the-source-w","errorCode":null,"errorMessage":"subject filter '%s' for the source: %w","messagePattern":"subject filter '(.+?)' for the source: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":964,"sourceCode":"\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\n\t// Setup our internal indexed names here for sources and check if the transforms (if any) are valid.\n\tfor _, ssi := range cfg.Sources {\n\t\tif len(ssi.SubjectTransforms) == 0 {\n\t\t\t// check the filter, if any, is valid\n\t\t\tif ssi.FilterSubject != _EMPTY_ && !IsValidSubject(ssi.FilterSubject) {\n\t\t\t\tjsa.mu.Unlock()\n\t\t\t\treturn nil, fmt.Errorf(\"subject filter '%s' for the source: %w\", ssi.FilterSubject, ErrBadSubject)\n\t\t\t}\n\t\t} else {\n\t\t\tfor _, st := range ssi.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(\"subject filter '%s' for the source: %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 source: %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":946,"sourceCodeEnd":982,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L946-L982","documentation":"Stream-creation validation for Sources: a source's FilterSubject is set but IsValidSubject rejected it — invalid characters or malformed wildcard placement in the source's subject filter. The filter string is echoed and the error wraps ErrBadSubject.","triggerScenarios":"AddStream/UpdateStream with cfg.Sources[i].FilterSubject invalid (malformed wildcard, double dots, illegal characters).","commonSituations":"Multi-source streams filtering subsets of upstream streams with a hand-typed filter, often copied between sources or templated from user input.","solutions":["Fix the source's FilterSubject to a valid subject string.","Drop the filter to consume the whole upstream stream.","Validate the filter with IsValidSubject before building the config."],"exampleFix":"// before\nSources: []StreamSource{{Name: \"A\", FilterSubject: \"x..y\"}}\n// after\nSources: []StreamSource{{Name: \"A\", FilterSubject: \"x.y\"}}","handlingStrategy":"validation","validationCode":"for _, s := range cfg.Sources {\n  if s.FilterSubject != \"\" && !nats.IsValidSubject(s.FilterSubject) { return fmt.Errorf(\"bad source filter %q\", s.FilterSubject) }\n}","typeGuard":null,"tryCatchPattern":"_, err := js.AddStream(cfg)\nvar apiErr *nats.APIError\nif err != nil && errors.As(err, &apiErr) && errors.Is(err, nats.ErrBadSubject) { /* fix FilterSubject of offending source */ }","preventionTips":["Validate each source's FilterSubject individually.","Don't template filters from unvalidated user input."],"tags":["jetstream","stream-sources","subject","validation"],"backgroundTag":"invalid-nats-subject","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}