micro/go-micro · critical

error connecting to nats at %v with tls enabled (%v): %w

Error message

error connecting to nats at %v with tls enabled (%v): %w

What it means

This error wraps the underlying nats.go connection failure when establishing a NATS connection with TLS settings. The library reports the NATS server address and whether TLS was enabled so the developer can diagnose connectivity problems. The wrapped error (%w) contains the root cause (dial failure, TLS handshake failure, auth failure, timeout).

Source

Thrown at events/natsjs/nats.go:83

	}

	if len(options.Address) > 0 {
		nopts.Servers = strings.Split(options.Address, ",")
	}

	if options.Name != "" {
		nopts.Name = options.Name
	}

	if options.Username != "" && options.Password != "" {
		nopts.User = options.Username
		nopts.Password = options.Password
	}

	conn, err := nopts.Connect()
	if err != nil {
		tls := nopts.TLSConfig != nil
		return nil, nil, fmt.Errorf("error connecting to nats at %v with tls enabled (%v): %w", options.Address, tls, err)
	}

	js, err := conn.JetStream()
	if err != nil {
		conn.Close() // Close connection if JetStream context fails
		return nil, nil, fmt.Errorf("error while obtaining JetStream context: %w", err)
	}

	return conn, js, nil
}

// Publish a message to a topic.
func (s *stream) Publish(topic string, msg interface{}, opts ...events.PublishOption) error {
	// validate the topic
	if len(topic) == 0 {
		return events.ErrMissingTopic
	}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Verify the NATS server is reachable: nats --server=<address> connz or nc -vz host 4222.
  2. Check options.Address scheme (nats:// vs tls://) and match it with your TLSConfig settings.
  3. If TLS is enabled, ensure TLSConfig has correct RootCAs/InsecureSkipVerify and the server presents a valid cert.
  4. Verify username/password/token credentials match the server config.
  5. Inspect the wrapped error for the precise cause (dial tcp refused vs x509 vs authorization violation).

Example fix

// before
stream, err := natsjs.NewStream(natsjs.Options{Address: "nats://localhost:9222", TLSConfig: tlsCfg})
// after
stream, err := natsjs.NewStream(natsjs.Options{Address: "tls://localhost:4222", TLSConfig: tlsCfg})
Defensive patterns

Strategy: retry

Validate before calling

addr := opts.Address
if addr == "" { return errors.New("nats address required") }
host, port, _ := net.SplitHostPort(strings.TrimPrefix(strings.TrimPrefix(addr, "nats://"), "tls://"))
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), 3*time.Second)
if err != nil { return fmt.Errorf("nats unreachable: %w", err) }
conn.Close()

Type guard

func isNATSTLSIssue(err error) bool { return strings.Contains(err.Error(), "x509") || strings.Contains(err.Error(), "tls:") }

Try / catch

conn, js, err := connectToNatsJetStream(opts)
if err != nil {
	var netErr net.Error
	if errors.As(err, &netErr) { /* backoff and retry */ }
	if strings.Contains(err.Error(), "x509") { /* fix TLS trust */ }
	return fmt.Errorf("nats connect: %w", err)
}

Prevention

When it happens

Trigger: Calling events/natsjs.NewStream (via connectToNatsJetStream) when nopts.Connect() fails — e.g. no NATS server listening at options.Address, TLS handshake rejected, bad credentials, or network unreachable.

Common situations: NATS server not running or wrong port; using nats:// where tls:// or a TLSConfig is required; self-signed certificates without RootCAs configured; firewall blocking the port; stale credentials after auth was enabled on the server.

Understand the failure class

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/7c37d2e8edabf797. Report an issue: GitHub.