{"record":{"id":"a0c081b620a8d5b9","repo":"nats-io/nats-server","slug":"subject-transform-from-s-to-s-for-the-source","errorCode":null,"errorMessage":"subject transform from '%s' to '%s' for the source: %w","messagePattern":"subject transform from '(.+?)' to '(.+?)' for the source: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/stream.go","lineNumber":976,"sourceCode":"\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\n\t// Check for overlapping subjects with other streams.\n\t// These are not allowed for now.\n\tif jsa.subjectsOverlap(cfg.Subjects, nil) {\n\t\tjsa.mu.Unlock()\n\t\treturn nil, NewJSStreamSubjectOverlapError()\n\t}\n\n\t// Setup the internal clients.\n\tc := s.createInternalJetStreamClient()\n\tic := s.createInternalJetStreamClient()\n\n\t// Work out the stream ingest limits.","sourceCodeStart":958,"sourceCodeEnd":994,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/stream.go#L958-L994","documentation":"Stream-creation validation for Sources: a Source.SubjectTransforms entry could not be constructed via NewSubjectTransform(source, destination) — the source/destination pair is not a valid subject transform (bad subject syntax or invalid wildcard usage in the mapping). The failing pair and underlying transform error are echoed.","triggerScenarios":"AddStream/UpdateStream where cfg.Sources[i].SubjectTransforms has a Destination that does not map from its Source (token-count or wildcard mismatch).","commonSituations":"Rewriting subjects across sourced streams with mismatched patterns, e.g. source \"a.*\" mapped to a three-token destination.","solutions":["Make source and destination token structures compatible (wildcards map 1:1).","Run NewSubjectTransform locally to reproduce the exact reason.","Empty the destination if no transform is needed for that source."],"exampleFix":"// before\n{Source: \"a.*\", Destination: \"b.*.c\"}\n// after\n{Source: \"a.*\", Destination: \"b.*\"}","handlingStrategy":"validation","validationCode":"for _, s := range cfg.Sources {\n  for _, st := range s.SubjectTransforms {\n    if st.Destination != \"\" {\n      if _, err := server.NewSubjectTransform(st.Source, st.Destination); err != nil { return err }\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"_, err := js.AddStream(cfg)\nif err != nil && strings.Contains(err.Error(), \"subject transform from\") { /* fix token mapping, resubmit */ }","preventionTips":["Match source/destination token counts and wildcard positions.","Validate transform pairs with NewSubjectTransform before deploy."],"tags":["jetstream","stream-sources","subject-transform","validation"],"backgroundTag":"subject-transform-invalid-mapping","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}