micro/go-micro · error

reflection list services returned %T

Error message

reflection list services returned %T

What it means

loadReflectedFiles expects the first message on the reflection stream to be a ListServicesResponse. If the server reflection response carries a different MessageResponse variant (e.g. an ErrorResponse or FileDescriptorResponse), this type-mismatch error is returned, naming the unexpected Go type received.

Source

Thrown at gateway/mcp/grpcreflect.go:126

	return out, nil
}

func loadReflectedFiles(ctx context.Context, conn *grpc.ClientConn) (*protoregistryFiles, []string, error) {
	client := reflectionpb.NewServerReflectionClient(conn)
	stream, err := client.ServerReflectionInfo(ctx)
	if err != nil {
		return nil, nil, err
	}
	if err := stream.Send(&reflectionpb.ServerReflectionRequest{MessageRequest: &reflectionpb.ServerReflectionRequest_ListServices{ListServices: ""}}); err != nil {
		return nil, nil, err
	}
	resp, err := stream.Recv()
	if err != nil {
		return nil, nil, err
	}
	list := resp.GetListServicesResponse()
	if list == nil {
		return nil, nil, fmt.Errorf("reflection list services returned %T", resp.MessageResponse)
	}

	set := &descriptorpb.FileDescriptorSet{}
	seen := map[string]bool{}
	var services []string
	for _, svc := range list.Service {
		name := svc.Name
		if strings.HasPrefix(name, "grpc.reflection.") {
			continue
		}
		services = append(services, name)
		if err := requestFileContainingSymbol(ctx, client, name, set, seen); err != nil {
			return nil, nil, err
		}
	}
	files, err := newProtoregistryFiles(set)
	if err != nil {
		return nil, nil, err

View on GitHub (pinned to 24529f1404)

Solutions

  1. Log the received %T to see which response variant came back (most likely ErrorResponse) and handle its message.
  2. Ensure the target supports the LIST_SERVICES reflection request (reflection.Register on the server).
  3. Check the server's reflection/grpc version and upgrade mismatched clients/servers.
  4. Inspect any proxy between client and server that could alter reflection responses.

Example fix

// before (server)
// reflection partially wired; handler returns error for list
// after (server)
reflection.Register(server) // guarantees ListServicesResponse for LIST_SERVICES
Defensive patterns

Strategy: type-guard

Type guard

func asListServices(resp *refpb.ServerReflectionResponse) *refpb.ListServicesResponse {
    if list := resp.GetListServicesResponse(); list != nil {
        return list
    }
    if errResp := resp.GetErrorResponse(); errResp != nil {
        log.Printf("reflection list failed: %s", errResp.GetErrorText())
    }
    return nil
}

Try / catch

if list == nil {
    if e := resp.GetErrorResponse(); e != nil {
        return fmt.Errorf("reflection list error from server: %s", e.GetErrorText())
    }
    return fmt.Errorf("reflection list services returned %T", resp.MessageResponse)
}

Prevention

When it happens

Trigger: requesting service listing via the ServerReflectionInfo stream and stream.Recv() returns a response whose GetListServicesResponse() is nil — the server answered with another message type instead of the list.

Common situations: A server behind a proxy mangling reflection responses; a server returning ErrorResponse for the LIST_SERVICES request (e.g. reflection partially disabled); version skew between reflection protocol implementations.

Related errors


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