{"record":{"id":"387d006fcfba18ba","repo":"stride3d/stride","slug":"the-type-doesn-t-have-an-assembly-qualified-name","errorCode":null,"errorMessage":"The type doesn't have an assembly-qualified name","messagePattern":"The type doesn't have an assembly-qualified name","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core/Annotations/DynamicTypeAttributeBase.cs","lineNumber":19,"sourceCode":"// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)\n// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.\n\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Stride.Core.Annotations;\n\n/// <summary>\n/// Base class for a dynamic type attribute.\n/// </summary>\npublic abstract class DynamicTypeAttributeBase : Attribute\n{\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DynamicTypeAttributeBase\"/> class.\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    protected DynamicTypeAttributeBase([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)\n    {\n        TypeName = type.AssemblyQualifiedName ?? throw new ArgumentException(\"The type doesn't have an assembly-qualified name\", nameof(type));\n    }\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"DynamicTypeAttributeBase\"/> class.\n    /// </summary>\n    /// <param name=\"typeName\">The type.</param>\n    protected DynamicTypeAttributeBase(string typeName)\n    {\n        TypeName = typeName;\n    }\n\n    /// <summary>\n    /// Gets the name of the <see cref=\"DynamicTypeAttributeBase\"/> type\n    /// </summary>\n    /// <value>The name of the serializable type.</value>\n    public string TypeName { get; }\n}\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core/Annotations/DynamicTypeAttributeBase.cs#L1-L37","documentation":"DynamicTypeAttributeBase stores a Type as TypeName using Type.AssemblyQualifiedName so editors/serializers can later resolve and instantiate it dynamically. For some types — notably open generic type parameters (the T itself) and certain dynamic or trimmed types — AssemblyQualifiedName returns null. Since the type could never be resolved by name later, the constructor throws ArgumentException immediately.","triggerScenarios":"Calling a derived attribute's constructor with typeof(T) where T is a generic type parameter; passing a Type instance captured from generic context at runtime; reflection-emit types with no assembly-qualified name.","commonSituations":"Writing a custom attribute deriving from DynamicTypeAttributeBase and forwarding a generic parameter to 'genericize' helper code; AOT/trimming scenarios; refactor from typeof(ConcreteType) to typeof(T).","solutions":["Pass a closed, concrete Type (e.g. typeof(MyConcreteType)) instead of a generic type parameter.","Move the attribute application to a non-generic context where the concrete type is known.","Check type.AssemblyQualifiedName != null before constructing and fall back to the typeName string constructor with a valid name."],"exampleFix":"// before\nvar attr = new MyDynamicTypeAttribute(typeof(T)); // throws: T has no assembly-qualified name\n\n// after\nvar attr = new MyDynamicTypeAttribute(typeof(ConcreteHandler)); // closed type with a valid AQN","handlingStrategy":"type-guard","validationCode":"if (candidateType.AssemblyQualifiedName == null)\n    throw new InvalidOperationException($\"{candidateType} cannot be used with DynamicTypeAttributeBase\");","typeGuard":"static bool HasAssemblyQualifiedName([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type? t) =>\n    t is not null && t.AssemblyQualifiedName is not null;","tryCatchPattern":"try\n{\n    var attr = new MyDynamicTypeAttribute(theType);\n}\ncatch (ArgumentException ex) when (ex.ParamName == \"type\")\n{\n    // fall back to a concrete closed type or log a configuration error\n}","preventionTips":["Never forward bare generic type parameters (typeof(T)) into dynamic-type attributes.","Apply these attributes only on closed, concrete types.","Write a startup self-check that constructs all configured attributes in a test."],"tags":["csharp","stride-core","reflection","generics"],"backgroundTag":"invalid-argument-value","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}