nats-io/nats-server · error

invalid domain name: derived

Error message

invalid domain name: derived %q is not a valid subject

What it means

The server-wide `jetstream_domain` option (o.JetStreamDomain) is also embedded into an API subject via jsDomainAPI and must therefore yield a valid NATS subject. Validation happens before the stricter character check, so this error fires first for domains that break subject syntax (invalid characters, empty tokens, bad wildcards).

Solutions

  1. Correct `jetstream_domain` so the derived subject is valid: use only alphanumeric, underscore, hyphen and dot characters, with no spaces or empty segments.
  2. Remove the `jetstream_domain` option if a single default domain is intended.
  3. Restart the server to re-run validation.

Example fix

// before
jetstream_domain: ".foo."
// after
jetstream_domain: "foo"
Defensive patterns

Strategy: validation

Validate before calling

if cfg.JetStreamDomain != "" {
    sub := "$JS." + cfg.JetStreamDomain + ".API"
    if !nats.IsValidSubject(sub) {
        return fmt.Errorf("jetstream_domain %q derives invalid subject", cfg.JetStreamDomain)
    }
}

Prevention

When it happens

Trigger: Configuring `jetstream_domain` in the server config with a value where fmt.Sprintf(jsDomainAPI, domain) is not a valid subject — e.g. containing spaces, leading/trailing dots, or invalid characters.

Common situations: Misconfigured multi-domain setups; environment-specific config templating injecting an empty or whitespace-padded domain; using reserved wildcard characters in the domain.

Related errors


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

Appendix: source

Thrown at server/jetstream.go:2929

		for a, d := range o.JsAccDefaultDomain {
			sacc := DEFAULT_SYSTEM_ACCOUNT
			if o.SystemAccount != _EMPTY_ {
				sacc = o.SystemAccount
			}
			if a == sacc {
				return fmt.Errorf("system account %q can not be in default_js_domain", a)
			}
			if d == _EMPTY_ {
				continue
			}
			if sub := fmt.Sprintf(jsDomainAPI, d); !IsValidSubject(sub) {
				return fmt.Errorf("default_js_domain contains account %q with invalid domain name %q", a, d)
			}
		}
	}
	if o.JetStreamDomain != _EMPTY_ {
		if subj := fmt.Sprintf(jsDomainAPI, o.JetStreamDomain); !IsValidSubject(subj) {
			return fmt.Errorf("invalid domain name: derived %q is not a valid subject", subj)
		}

		if !isValidName(o.JetStreamDomain) {
			return fmt.Errorf("invalid domain name: may not contain ., * or >")
		}
	}
	// If not clustered no checks needed past here.
	if !o.JetStream || o.Cluster.Port == 0 {
		return nil
	}
	if o.ServerName == _EMPTY_ {
		return fmt.Errorf("jetstream cluster requires `server_name` to be set")
	}
	if o.Cluster.Name == _EMPTY_ {
		return fmt.Errorf("jetstream cluster requires `cluster.name` to be set")
	}

	h := strings.ToLower(o.JetStreamExtHint)

View on GitHub (pinned to 3a66a489d2)