You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
System.Text.Json source generator emits duplicate __GenericAccessors_ wrapper class for inaccessible members inherited from multiple generic base types #133423
The System.Text.Json source generator emits colliding helper classes for inaccessible members (e.g. a private [JsonInclude] property) that are inherited from two different generic base types of the same arity. The generated code then fails to compile with an error like CS0102: The type 'MyContext' already contains a definition for '__GenericAccessors_Leaf' (plus possibly a cascade of CS0264/CS0265/CS0699/CS0246).
This is a compilation failure that only happens in .NET 11; the same program compiles on .NET 10 (with a SYSLIB1038 warning), but then throws an InvalidOperationException when you attempt to use the generated serializer context.
Under .NET 10 the source generator does not emit accessors for inaccessible members: it reports SYSLIB1038 and the type throws InvalidOperationException at run time. Under .NET 11 the generator now emits [UnsafeAccessor] accessor wrapper classes for inaccessible members (added in #124650), but for members inherited from two different generic base types of the same arity the wrapper classes collide and the generated code no longer compiles.
> dotnet run -f net10.0
C:\code\tmp\hwapp\Program.cs(15,16): warning SYSLIB1038: The member 'Base.BaseSecret' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1038)
C:\code\tmp\hwapp\Program.cs(9,16): warning SYSLIB1038: The member 'GrandBase.GrandSecret' has been annotated with the JsonIncludeAttribute but is not visible to the source generator. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1038)
Unhandled exception. System.InvalidOperationException: The property 'BaseSecret' on type 'Base`1[System.Int32]' which is annotated with 'JsonIncludeAttribute' is not accesible by the source generator.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnInaccessibleProperty(String memberName, Type declaringType)
at System.Text.Json.Serialization.Metadata.JsonMetadataServices.PopulateProperties(JsonTypeInfo typeInfo, JsonPropertyInfoList propertyList, Func`2 propInitFunc)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<get_PropertyList>g__CreatePropertyList|63_0()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.ConfigureProperties()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.<EnsureConfigured>g__ConfigureSynchronized|174_0()
at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
at System.Text.Json.JsonSerializerOptions.GetTypeInfo(Type type)
at MyContext.get_Leaf() in ...\MyContext.Leaf.g.cs:line 20
at Program.<Main>$(String[] args) in C:\code\tmp\hwapp\Program.cs:line 4
> dotnet run -f net11.0
...\MyContext.Leaf.g.cs(121,26): error CS0102: The type 'MyContext' already contains a definition for '__GenericAccessors_Leaf'
...\MyContext.Leaf.g.cs(113,26): error CS0264: Partial declarations of 'MyContext.__GenericAccessors_Leaf<TB>' must have the same type parameter names in the same order
...\MyContext.Leaf.g.cs(121,60): error CS0699: 'MyContext.__GenericAccessors_Leaf<TB>' does not define type parameter 'TG'
...\MyContext.Leaf.g.cs(113,26): error CS0265: Partial declarations of 'MyContext.__GenericAccessors_Leaf<TB>' have inconsistent constraints for type parameter 'TB'
...\MyContext.Leaf.g.cs(124,74): error CS0246: The type or namespace name 'TG' could not be found (are you missing a using directive or an assembly reference?)
...\MyContext.Leaf.g.cs(124,30): error CS0246: The type or namespace name 'TG' could not be found (are you missing a using directive or an assembly reference?)
...\MyContext.Leaf.g.cs(126,76): error CS0246: The type or namespace name 'TG' could not be found (are you missing a using directive or an assembly reference?)
...\MyContext.Leaf.g.cs(126,85): error CS0246: The type or namespace name 'TG' could not be found (are you missing a using directive or an assembly reference?)
The build failed. Fix the build errors and run again.
(Reproduced on SDK 11.0.100-rc.2.26431.116; the net10.0 run used the .NET 10 GA shared framework.)
Root cause
The generator emits one member-accessor wrapper class per declaring type (keyed by property.DeclaringType.FullyQualifiedName), but names each one only after the constructed type:
// JsonSourceGenerator.Emitter.cswriter.WriteLine($"private static class __GenericAccessors_{typeFriendlyName}<{typeParamList}>{constraintClauses}");
Here typeFriendlyName is the constructed type's TypeInfoPropertyName and typeParamList/constraintClauses come from the declaring type. When a type has inaccessible members inherited from two different generic base types of the same arity, both wrappers are emitted as __GenericAccessors_Leaf<...> with arity 1, so C# sees the same type defined twice.
Proposed fix
Include a declaring-type discriminator in the wrapper class name so each declaring type gets a distinct wrapper (analogous to how the per-member accessor methods are already disambiguated).
The different type parameter names and constraints are not not necessary to reproduce the issue, but show that each base class requires a separate wrapper class.
Note
This issue (including the reproduced output) was created with the help of GitHub Copilot.
Description
The System.Text.Json source generator emits colliding helper classes for inaccessible members (e.g. a
private [JsonInclude]property) that are inherited from two different generic base types of the same arity. The generated code then fails to compile with an error likeCS0102: The type 'MyContext' already contains a definition for '__GenericAccessors_Leaf'(plus possibly a cascade of CS0264/CS0265/CS0699/CS0246).This is a compilation failure that only happens in .NET 11; the same program compiles on .NET 10 (with a SYSLIB1038 warning), but then throws an
InvalidOperationExceptionwhen you attempt to use the generated serializer context.Repro
Program.cs:hwapp.csproj(multi-targeted to show the difference):Behavior change between .NET 10 and .NET 11
Under .NET 10 the source generator does not emit accessors for inaccessible members: it reports
SYSLIB1038and the type throwsInvalidOperationExceptionat run time. Under .NET 11 the generator now emits[UnsafeAccessor]accessor wrapper classes for inaccessible members (added in #124650), but for members inherited from two different generic base types of the same arity the wrapper classes collide and the generated code no longer compiles.(Reproduced on SDK
11.0.100-rc.2.26431.116; thenet10.0run used the .NET 10 GA shared framework.)Root cause
The generator emits one member-accessor wrapper class per declaring type (keyed by
property.DeclaringType.FullyQualifiedName), but names each one only after the constructed type:Here
typeFriendlyNameis the constructed type'sTypeInfoPropertyNameandtypeParamList/constraintClausescome from the declaring type. When a type has inaccessible members inherited from two different generic base types of the same arity, both wrappers are emitted as__GenericAccessors_Leaf<...>with arity 1, so C# sees the same type defined twice.Proposed fix
Include a declaring-type discriminator in the wrapper class name so each declaring type gets a distinct wrapper (analogous to how the per-member accessor methods are already disambiguated).
Notes
Note
This issue (including the reproduced output) was created with the help of GitHub Copilot.