Skip to content

[Bug]: Custom-code references to generated (un-stubbed) types emit empty namespace ( global::.TypeName ) #11060

Description

@rhurey

Describe the bug

Summary

When custom code references a generated type that is not also declared in the customization compilation (no  [CodeGenType]  stub / partial), the generator emits the type with an empty namespace, e.g.:

IDictionary<string, global::.ToolConfig> toolConfigs = default

This produces uncompilable output. Observed in  Azure.AI.Extensions.OpenAI  for  ToolConfig  and the enum  ResponsesToolSearchExecutionType , surfaced in the generated  ExtensionsOpenAIModelFactory .

Root cause

• The customization Roslyn compilation ( SourceInputModel.Customization ) is built from custom files only; generated sources are not part of it.
• Generated types referenced by custom code normally resolve because the library declares a stub (e.g.  [CodeGenType("BingGroundingSearchToolParameters")] ). Types without a stub resolve to Roslyn error type symbols.
•  TypeSymbolExtensions.GetCSharpType  →  ConstructCSharpTypeFromSymbol  builds a  CSharpType  from the error symbol. The fully-qualified display string of an unresolved symbol carries no namespace, so:
// TypeSymbolExtensions.cs (~line 204)
string[] pieces = fullyQualifiedName.Split('`')[0].Split('.'); // ["ToolConfig"]
string ns = string.Join('.', pieces.Take(pieces.Length - 1)); // "" (empty)
• The empty namespace flows into a real type used by  ModelFactoryProvider  (the factory derives parameter types from the model's full constructor, which here lives in custom code), producing  global::.ToolConfig .

Why it only shows in the model factory

The generated model itself is in the same namespace, so the writer emits the short name  ToolConfig  and the empty namespace is invisible. The model factory (with  using OpenAI.Responses; ) qualifies the type, exposing the empty namespace.

Affected code

 Microsoft.TypeSpec.Generator/src/Utilities/TypeSymbolExtensions.cs  —  ConstructCSharpTypeFromSymbol  (namespace computation for error-type symbols).

Suggested fix

When the symbol is an unresolved error type ( TypeKind.Error ) and the computed namespace is empty, fall back to the output library by name via  CodeModelGenerator.Instance.TypeFactory.TypeProvidersByName  (already maintained,  TypeFactory.cs:29 ) to recover the real  CSharpType /namespace. This is a best-effort fallback that triggers only for otherwise-broken symbols, so resolved types are unaffected, and it fixes the class of bug for any library — not just those that add  [CodeGenType]  stubs.

Current workaround

Add a stub for each affected type in custom code, e.g.  [CodeGenType("ToolConfig")] public partial class ToolConfig { } .

Reproduction

Repro

  1. Generated type  Foo  exists (no  [CodeGenType]  stub in custom code).
  2. A custom-code constructor parameter references  Foo  (e.g.  IDictionary<string, Foo> ).
  3. That constructor is the full constructor used by the model factory.
  4. Generated factory contains  global::.Foo .

Checklist

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't workingemitter:client:csharpIssue for the C# client emitter: @typespec/http-client-csharp

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions