Skip to content

[Source Generator] Cross-assembly pagination types lose generic arguments in ConnectionTypeFileBuilder #10141

Description

@MarkArchitect

Product

Hot Chocolate

Version

15.., 16..

Link to minimal reproduction

https://github.com/MarkArchitect/BugSample/blob/main/BugSample.zip

Steps to reproduce

  1. Create a Shared Library with a domain model: public class Book { ... }
  2. Create an Extension Library with a custom closed connection:

public sealed class BookPageConnection(Page<Book> page, int maxRelativeCursorCount = 5)
    : PageConnection<Book>(page, maxRelativeCursorCount)
{
}
  1. In the Main Web/API project, reference the Extension Library and create a resolver:
[ObjectType<AuthorWithData>]
public static partial class AuthorWithDataNode
{
    [UseConnection]
    public static async Task<BookPageConnection> BooksV2(
        QueryContext<Book> query, 
        IResolverContext resolverContext)
    {
        return new BookPageConnection(Page<Book>.Empty, 5);
    }
}

  1. Compile the Main project.
  2. You get error:
    The type or namespace name 'PageEdge' does not exist in the namespace 'Extension.Shared' (are you missing an assembly reference?)
  3. If BookPageConnection class is in main project it compiles fine

What is expected?

The Source Generator should inspect the semantic model/type symbols correctly regardless of assembly boundaries. Instead of manual string assembly, it should construct the fully qualified generic name using ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat).

The expected output inside the .Type<...>() descriptor method should be:

.Type<global::HotChocolate.Types.ListType<global::HotChocolate.Types.NonNullType<global::HotChocolate.Types.Pagination.PageEdge<global::Lib.Shared.Book>>>>()

Or it should point directly to the generated GraphQL type wrapper:

.Type<global::HotChocolate.Types.ListType<global::HotChocolate.Types.NonNullType<global::Extension.Shared.BookPageEdgeType>>>()

What is actually happening?

The Source Generator successfully creates BookPageEdgeType for PageEdge, but when generating the BookPageConnectionType, it falls back to raw string concatenation.

In ConnectionTypeFileBuilder.cs, the generator relies on connectionType.Namespace and connectionType.EdgeTypeName:

var edgeTypeName = $"{connectionType.Namespace}.{connectionType.EdgeTypeName}";

Because the metadata is read from an external compiled .dll instead of a local syntax tree, connectionType.EdgeTypeName evaluates to a bare string "PageEdge" without its generic type parts.

This produces the following invalid, non-compilable chunk in the generated file:

descriptor
    .Field(thisType.GetMember("Edges", global::HotChocolate.Utilities.ReflectionUtils.InstanceMemberFlags)[0])
    .Type<global::HotChocolate.Types.ListType<global::HotChocolate.Types.NonNullType<global::Extension.Shared.PageEdge>>>()

The compiler throws a severe error because global::Extension.Shared.PageEdge (or global::HotChocolate.Types.Pagination.PageEdge) is being passed without its generic parameters, breaking C# syntax: "Type PageEdge requires 1 type arguments".

Relevant log output

Severity	Code	Description	Project	File	Line	Suppression State	Details
Error (active)	CS0234	The type or namespace name 'PageEdge' does not exist in the namespace 'Lib.Shared.Types' (are you missing an assembly reference?)	MainProject	C:\\BugSample\MainProject\obj\Debug\net8.0\HotChocolate.Types.Analyzers\HotChocolate.Types.Analyzers.GraphQLServerGenerator\BookPageConnectionType.fLGrviozGWgIjRnrCfn0Fg.hc.g.cs	29

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions