stride3d/stride · error · ArgumentException

The type doesn't have an assembly-qualified name

Error message

The type doesn't have an assembly-qualified name

What it means

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.

Solutions

  1. Pass a closed, concrete Type (e.g. typeof(MyConcreteType)) instead of a generic type parameter.
  2. Move the attribute application to a non-generic context where the concrete type is known.
  3. Check type.AssemblyQualifiedName != null before constructing and fall back to the typeName string constructor with a valid name.

Example fix

// before
var attr = new MyDynamicTypeAttribute(typeof(T)); // throws: T has no assembly-qualified name

// after
var attr = new MyDynamicTypeAttribute(typeof(ConcreteHandler)); // closed type with a valid AQN
Defensive patterns

Strategy: type-guard

Validate before calling

if (candidateType.AssemblyQualifiedName == null)
    throw new InvalidOperationException($"{candidateType} cannot be used with DynamicTypeAttributeBase");

Type guard

static bool HasAssemblyQualifiedName([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type? t) =>
    t is not null && t.AssemblyQualifiedName is not null;

Try / catch

try
{
    var attr = new MyDynamicTypeAttribute(theType);
}
catch (ArgumentException ex) when (ex.ParamName == "type")
{
    // fall back to a concrete closed type or log a configuration error
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/387d006fcfba18ba. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core/Annotations/DynamicTypeAttributeBase.cs:19

// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Diagnostics.CodeAnalysis;

namespace Stride.Core.Annotations;

/// <summary>
/// Base class for a dynamic type attribute.
/// </summary>
public abstract class DynamicTypeAttributeBase : Attribute
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DynamicTypeAttributeBase"/> class.
    /// </summary>
    /// <param name="type">The type.</param>
    protected DynamicTypeAttributeBase([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
    {
        TypeName = type.AssemblyQualifiedName ?? throw new ArgumentException("The type doesn't have an assembly-qualified name", nameof(type));
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DynamicTypeAttributeBase"/> class.
    /// </summary>
    /// <param name="typeName">The type.</param>
    protected DynamicTypeAttributeBase(string typeName)
    {
        TypeName = typeName;
    }

    /// <summary>
    /// Gets the name of the <see cref="DynamicTypeAttributeBase"/> type
    /// </summary>
    /// <value>The name of the serializable type.</value>
    public string TypeName { get; }
}

View on GitHub (pinned to 96fad776d2)