micro/go-micro · error

failed to discover services: %w

Error message

failed to discover services: %w

What it means

After building the Server struct, NewServer calls server.discoverServices(), which queries the registry and builds the tool list from discovered services. Any error returned by discovery is wrapped with "failed to discover services: %w" so the underlying registry failure (connection refused, timeout, auth) is preserved in the chain.

Source

Thrown at gateway/mcp/mcp.go:278

		opts.Context = context.Background()
	}
	if opts.Logger == nil {
		opts.Logger = log.Default()
	}
	if opts.Registry == nil {
		return nil, fmt.Errorf("registry is required")
	}

	server := &Server{
		opts:     opts,
		tools:    make(map[string]*Tool),
		limiters: make(map[string]*rateLimiter),
		breakers: make(map[string]*circuitBreaker),
	}

	// Discover services and build tool list
	if err := server.discoverServices(); err != nil {
		return nil, fmt.Errorf("failed to discover services: %w", err)
	}

	// Watch for service changes
	go server.watchServices()

	return server, nil
}

// Serve starts an MCP gateway with the given options.
// For stdio transport, leave Address empty.
// For SSE transport, set Address (e.g., ":3000").
func Serve(opts Options) error {
	server, err := NewServer(opts)
	if err != nil {
		return err
	}
	return server.Serve()
}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read the wrapped %w cause to identify the registry failure (e.g. connection refused to etcd/consul).
  2. Verify the registry backend is running and reachable: check REGISTRY_ADDRESSES / registry options and network connectivity.
  3. Ensure services are actually registered before starting the gateway, or retry NewServer with backoff once the registry is available.
  4. If mdns, confirm multicast is allowed in the container/host network.

Example fix

// before
srv, err := mcp.NewServer(opts) // registry unreachable, fails
// after
if err := reg.Init(registry.Addrs("etcd:2379")); err != nil { log.Fatal(err) }
for i := 0; i < 5; i++ {
    srv, err = mcp.NewServer(mcp.Options{Registry: reg})
    if err == nil { break }
    time.Sleep(2 * time.Second)
}
Defensive patterns

Strategy: retry

Validate before calling

// verify registry reachability before NewServer
if _, err := reg.ListServices(context.Background()); err != nil {
    return fmt.Errorf("registry unreachable: %w", err)
}

Try / catch

srv, err := mcp.NewServer(opts)
if err != nil {
    var rerr error
    if errors.As(err, &rerr) && strings.Contains(err.Error(), "failed to discover services") {
        // retry with backoff; log wrapped cause with errors.Unwrap
    }
}

Prevention

When it happens

Trigger: NewServer is called with a valid non-nil Registry, but discoverServices fails — e.g. the registry backend (etcd/consul/mdns) is unreachable, the registry returns malformed service data, or ListServices/GetService returns an error.

Common situations: Registry server down or wrong registry address configured; network partition between gateway and registry; registry credentials rejected; using mdns in an environment that blocks multicast; services registered with metadata the gateway cannot parse.

Related errors


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