{"record":{"id":"1d90949ae20c8f6d","repo":"nats-io/nats-server","slug":"10155","errorCode":"10155","errorMessage":"%w %s","messagePattern":"%w %s","errorType":"validation","errorClass":"ApiError (JSStreamTransformInvalidSource)","httpStatus":400,"severity":"error","filePath":"server/stream.go","lineNumber":2421,"sourceCode":"\t\t}\n\t}\n\n\tif len(cfg.Subjects) == 0 && len(cfg.Sources) == 0 && cfg.Mirror == nil {\n\t\treturn StreamConfig{}, NewJSStreamInvalidConfigError(\n\t\t\tfmt.Errorf(\"stream needs at least one configured subject or be a source/mirror\"))\n\t}\n\n\t// Check for MaxBytes required and it's limit\n\tif required, limit := acc.maxBytesLimits(&cfg); required && cfg.MaxBytes <= 0 {\n\t\treturn StreamConfig{}, NewJSStreamMaxBytesRequiredError()\n\t} else if limit > 0 && cfg.MaxBytes > limit {\n\t\treturn StreamConfig{}, NewJSStreamMaxStreamBytesExceededError()\n\t}\n\n\t// Check the subject transform if any\n\tif cfg.SubjectTransform != nil {\n\t\tif cfg.SubjectTransform.Source != _EMPTY_ && !IsValidSubject(cfg.SubjectTransform.Source) {\n\t\t\treturn StreamConfig{}, NewJSStreamTransformInvalidSourceError(fmt.Errorf(\"%w %s\", ErrBadSubject, cfg.SubjectTransform.Source))\n\t\t}\n\n\t\terr := ValidateMapping(cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination)\n\t\tif err != nil {\n\t\t\treturn StreamConfig{}, NewJSStreamTransformInvalidDestinationError(err)\n\t\t}\n\t}\n\n\t// If we have a republish directive check if we can create a transform here.\n\tif cfg.RePublish != nil {\n\t\t// Check to make sure source is a valid subset of the subjects we have.\n\t\t// Also make sure it does not form a cycle.\n\t\t// Empty same as all.\n\t\tif cfg.RePublish.Source == _EMPTY_ {\n\t\t\tif pedantic {\n\t\t\t\treturn StreamConfig{}, NewJSPedanticError(fmt.Errorf(\"republish source can not be empty\"))\n\t\t\t}\n\t\t\tcfg.RePublish.Source = fwcs","sourceCodeStart":2403,"sourceCodeEnd":2439,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L2403-L2439","documentation":"The stream's SubjectTransform.Source is not a valid NATS subject, so the transform cannot be applied. The error wraps ErrBadSubject together with the offending source string. NATS validates the transform's source strictly because republished/transformed messages depend on a well-formed subject to rewrite into the destination.","triggerScenarios":"StreamConfig.Add/Update with cfg.SubjectTransform = &nats.SubjectTransform{Source: \"not a subject\"} — strings with spaces, empty source, or illegal wildcard placement (e.g. 'foo.**' or a token like 'foo.>'). Check runs whenever SubjectTransform != nil and Source is non-empty.","commonSituations":"User-supplied transform configuration interpolated into StreamConfig without validation; template variables not substituted (e.g. Source: \"{{subject}}\"); trailing whitespace or typos in config files.","solutions":["Fix cfg.SubjectTransform.Source to a valid NATS subject (letters, digits, '_' '-' '/', '*' per token, '>' only as last token).","Validate the string with nats.IsValidSubject (or server.IsValidSubject) before submitting the config.","Trim whitespace or resolve unsubstituted template variables before calling AddStream."],"exampleFix":"// before\njs.AddStream(&nats.StreamConfig{Name: \"s\", Subjects: []string{\"events.>\"}, SubjectTransform: &nats.SubjectTransform{Source: \"events .>\"}})\n// after\njs.AddStream(&nats.StreamConfig{Name: \"s\", Subjects: []string{\"events.>\"}, SubjectTransform: &nats.SubjectTransform{Source: \"events.>\", Destination: \"archive.events.>\"}})","handlingStrategy":"validation","validationCode":"func validTransformSource(t *nats.SubjectTransform) error {\n  if t == nil { return nil }\n  if t.Source == \"\" { return nil }\n  if !isValidSubject(t.Source) {\n    return fmt.Errorf(\"transform source %q is not a valid subject\", t.Source)\n  }\n  return nil\n}","typeGuard":"func hasValidTransformSource(t *nats.SubjectTransform) bool {\n  return t == nil || t.Source == \"\" || isValidSubject(t.Source)\n}","tryCatchPattern":"var jsErr *nats.JSApiError\nif _, err := js.AddStream(cfg); err != nil {\n  if errors.As(err, &jsErr) && errors.Is(err, nats.ErrBadSubject) || strings.Contains(err.Error(), \"bad subject\") {\n    log.Printf(\"fix SubjectTransform.Source: %v\", err)\n  }\n}","preventionTips":["Validate user-supplied transform subjects with the library's subject validator before submit","Trim and resolve template variables in config pipelines","Test transform configs against a local nats-server in CI"],"tags":["jetstream","stream-config","subject-transform","validation"],"backgroundTag":"invalid-subject","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}