nats-io/nats-server · error

stream subject transform from '%s' to '%s': %w

Error message

stream subject transform from '%s' to '%s': %w

What it means

Stream-creation validation: the stream-level cfg.SubjectTransform could not be constructed via NewSubjectTransform(source, destination); the input transform on the stream config is invalid (bad subject syntax, illegal wildcards in source/destination mapping). The offending pair and the transform error are wrapped in the message.

Source

Thrown at server/stream.go:1053

		// protection: sa.Created is immutable.
		mset.created = sa.Created
	}

	// Start our signaling routine to process consumers.
	mset.sigq = newIPQueue[*cMsg](s, qpfx+"obs") // of *cMsg
	go mset.signalConsumersLoop()

	// For no-ack consumers when we are interest retention.
	if cfg.Retention != LimitsPolicy {
		mset.ackq = newIPQueue[uint64](s, qpfx+"acks")
	}

	// Check for input subject transform
	if cfg.SubjectTransform != nil {
		tr, err := NewSubjectTransform(cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination)
		if err != nil {
			jsa.mu.Unlock()
			return nil, fmt.Errorf("stream subject transform from '%s' to '%s': %w", cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination, err)
		}
		mset.itr = tr
	}

	// Check for RePublish.
	if cfg.RePublish != nil {
		tr, err := NewSubjectTransform(cfg.RePublish.Source, cfg.RePublish.Destination)
		if err != nil {
			jsa.mu.Unlock()
			return nil, fmt.Errorf("stream republish transform from '%s' to '%s': %w", cfg.RePublish.Source, cfg.RePublish.Destination, err)
		}
		// Assign our transform for republishing.
		mset.tr = tr
	}
	storeDir := filepath.Join(jsa.storeDir, streamsDir, cfg.Name)
	jsa.mu.Unlock()

	// Bind to the user account.

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Align the destination's token structure with the source (each wildcard maps one token).
  2. Check both subjects with IsValidSubject and test with NewSubjectTransform before calling AddStream.
  3. Remove cfg.SubjectTransform if no stream-wide remap is intended.

Example fix

// before
SubjectTransform: &SubjectTransformConfig{Source: "events.*", Destination: "archive.events.*.v2"}
// after
SubjectTransform: &SubjectTransformConfig{Source: "events.*", Destination: "archive.events.*"}
Defensive patterns

Strategy: validation

Validate before calling

if cfg.SubjectTransform != nil {
  if _, err := server.NewSubjectTransform(cfg.SubjectTransform.Source, cfg.SubjectTransform.Destination); err != nil { return err }
}

Try / catch

_, err := js.AddStream(cfg)
if err != nil && strings.Contains(err.Error(), "stream subject transform") { /* fix transform, resubmit */ }

Prevention

When it happens

Trigger: AddStream with cfg.SubjectTransform whose Source/Destination pair is invalid: token-count mismatch, illegal wildcard usage, or invalid characters in either subject.

Common situations: Remapping all messages published to a stream into a different subject space; typical mistake is destination with more tokens than source or wildcards in the wrong token position.

Related errors


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