nats-io/nats-server · error

remote %s: %s

Error message

remote %s: %s

What it means

While diffing leaf node remotes during reload, checkConfigsEqual on a leaf remote (leafnodes.remotes[i]) returned an unsupported field change (TLSHandshakeFirst, TLSConfig, etc. are in the ignore list but the rest failed). The error is wrapped as remote <name>: <cause>.

Source

Thrown at server/reload.go:999

			if rlo == nil {
				// Not found, will be removed in leafNodeOption.Apply().
				removed = true
				lrc.RUnlock()
				continue
			}
			// Now we need to make sure that there are no changes that we don't
			// support for a RemoteLeafOpts.
			err := checkConfigsEqual(lrc.RemoteLeafOpts, rlo, []string{
				"Compression",
				"Disabled",
				"TLS",
				"TLSHandshakeFirst",
				"TLSConfig",
			})
			if err != nil {
				lrc.RUnlock()
				s.mu.RUnlock()
				return nil, fmt.Errorf(remoteErrFormat, rlo.safeName(), err)
			}
			disabledChanged := lrc.Disabled != rlo.Disabled
			// If this remote was disabled and is now enabled, we need to make sure
			// that there is no connect in progress. If that is the case, either
			// try again (if it is the first failure) or return an error.
			if disabledChanged && lrc.Disabled && lrc.connInProgress {
				lrc.RUnlock()
				s.mu.RUnlock()
				if failed < maxAttempts-1 {
					continue forLoop
				}
				return nil, fmt.Errorf(remoteErrFormat, rlo.safeName(),
					"cannot be enabled at the moment, try again")
			}
			// Since we will use the new `rlo.TLSConfig` later on, consider all
			// existing remote configs as "changed" and store them in the
			// `nlo.changed` map.
			if nlo.changed == nil {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Revert the unsupported remote field in the config, or restart the server to apply it.
  2. Restrict reload edits to supported remote fields (check NATS reload docs for the allow-list).
  3. Split changes: reload supported fields now; schedule a restart for the remote connection changes.

Example fix

// before (reload)
leafnodes { remotes: [ { url: "nats://other:4222", credentials: "new.creds" } ] }
// after
leafnodes { remotes: [ { url: "nats://other:4222", credentials: "old.creds" } ] } // restart to swap creds
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate that only hot-reloadable leaf remote fields changed
unsupported := []string{"credentials", "tls", "urls"}
for _, f := range unsupported {
    if remoteChanged(oldRemote, newRemote, f) {
        return fmt.Errorf("field %q of leaf remote requires restart", f)
    }
}

Try / catch

if err := srv.Reload(); err != nil {
    if strings.HasPrefix(err.Error(), "remote ") {
        log.Printf("leaf remote reload rejected, restart needed: %v", err)
    }
}

Prevention

When it happens

Trigger: Editing a field of an existing leafnodes.remotes[] entry that cannot be hot-reloaded (e.g. credentials, urls, TLS details) and calling Reload() or sending SIGHUP.

Common situations: Rotating leaf remote credentials or URLs via reload; adding/removing accounts in a remote entry; changing TLS material of a running remote connection.

Related errors


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