micro/go-micro · error

reflection lookup for %s returned %T

Error message

reflection lookup for %s returned %T

What it means

requestFileContainingSymbol asks the reflection stream for the file descriptor containing a given symbol and expects a FileDescriptorResponse. If the reply is a different MessageResponse variant (typically ErrorResponse, meaning the server does not know the symbol), this error reports the unexpected type received for that symbol.

Source

Thrown at gateway/mcp/grpcreflect.go:163

	}
	return files, services, nil
}

func requestFileContainingSymbol(ctx context.Context, client reflectionpb.ServerReflectionClient, symbol string, set *descriptorpb.FileDescriptorSet, seen map[string]bool) error {
	stream, err := client.ServerReflectionInfo(ctx)
	if err != nil {
		return err
	}
	if err := stream.Send(&reflectionpb.ServerReflectionRequest{MessageRequest: &reflectionpb.ServerReflectionRequest_FileContainingSymbol{FileContainingSymbol: symbol}}); err != nil {
		return err
	}
	resp, err := stream.Recv()
	if err != nil {
		return err
	}
	fd := resp.GetFileDescriptorResponse()
	if fd == nil {
		return fmt.Errorf("reflection lookup for %s returned %T", symbol, resp.MessageResponse)
	}
	for _, raw := range fd.FileDescriptorProto {
		var file descriptorpb.FileDescriptorProto
		if err := proto.Unmarshal(raw, &file); err != nil {
			return err
		}
		name := file.GetName()
		if !seen[name] {
			seen[name] = true
			set.File = append(set.File, &file)
		}
	}
	return nil
}

// protoregistryFiles is a narrow wrapper that keeps imports local to this file.
type protoregistryFiles struct{ files *protoregistry.Files }

View on GitHub (pinned to 24529f1404)

Solutions

  1. Inspect the ErrorResponse text (log the %T and the response's error message) to see why the symbol lookup failed.
  2. Ensure the server binary was built with the same .proto definitions it serves, so symbols resolve.
  3. Verify the symbol name format passed to requestFileContainingSymbol (fully qualified package.Service).
  4. Fall back to supplying descriptor sets (FileDescriptorSet) instead of per-symbol reflection if the server cannot resolve symbols.

Example fix

// before
symbol := "MyService" // not fully qualified
// after
symbol := "mypackage.MyService" // fully qualified symbol resolves via reflection
Defensive patterns

Strategy: type-guard

Validate before calling

if !strings.Contains(symbol, ".") {
    return fmt.Errorf("symbol %q must be fully qualified (package.Service)", symbol)
}

Type guard

func asFileDescriptor(resp *refpb.ServerReflectionResponse) *refpb.FileDescriptorResponse {
    if fd := resp.GetFileDescriptorResponse(); fd != nil {
        return fd
    }
    if errResp := resp.GetErrorResponse(); errResp != nil {
        log.Printf("symbol lookup failed: %s", errResp.GetErrorText())
    }
    return nil
}

Try / catch

if err := requestFileContainingSymbol(ctx, stream, symbol); err != nil {
    if strings.Contains(err.Error(), "returned refpb.ServerReflectionError") {
        return fmt.Errorf("server cannot resolve %s; check descriptor build parity: %w", symbol, err)
    }
    return err
}

Prevention

When it happens

Trigger: loadReflectedFiles resolving each listed service via requestFileContainingSymbol, and stream.Recv() returns a response whose GetFileDescriptorResponse() is nil — commonly an ErrorResponse for SYMBOL_TO_FILE_CONTAINING_SYMBOL.

Common situations: Server reflection enabled but built from different .proto files than the client expects (symbol not found); nested/legacy symbols the server cannot resolve; services registered without the corresponding descriptor source.

Related errors


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