stride3d/stride · error · ArgumentException
Type [{0}] is not a primitive
Error message
Type [{0}] is not a primitive What it means
The NullableDescriptor constructor only accepts Nullable<T> types (i.e. typeof(int?) and similar); it verifies with IsNullable(type) and throws ArgumentException 'Type [{0}] is not a primitive' when a non-nullable type is passed. Note the message uses '{0}' without string.Format, so the raw placeholder is displayed. This is an internal TypeDescriptor factory invariant — descriptors are built per-type by TypeDescriptorFactory.
Solutions
- Check Nullable.GetUnderlyingType(type) != null before constructing NullableDescriptor.
- Route non-nullable types to ObjectDescriptor/PrimitiveDescriptor via the normal TypeDescriptorFactory instead.
- Fix the dispatch predicate so only Nullable<T> types reach this constructor.
Example fix
// before
var descriptor = new NullableDescriptor(factory, typeof(int), false, namingConvention);
// after
if (Nullable.GetUnderlyingType(typeof(int?)) != null)
var descriptor = new NullableDescriptor(factory, typeof(int?), false, namingConvention); Defensive patterns
Strategy: validation
Validate before calling
if (Nullable.GetUnderlyingType(type) == null)
throw new InvalidOperationException($"{type} is not Nullable<T>; use the appropriate descriptor");
var d = new NullableDescriptor(factory, type, emitDefaultValues, namingConvention); Type guard
static bool IsNullableType(Type t) => Nullable.GetUnderlyingType(t) != null;
Try / catch
try { return new NullableDescriptor(factory, type, emit, conv); }
catch (ArgumentException) { return TypeDescriptorFactory.Default.FindDescriptor(type); } Prevention
- Check Nullable.GetUnderlyingType before constructing nullable descriptors.
- Let TypeDescriptorFactory dispatch types instead of instantiating descriptors manually.
- Add a unit test asserting descriptor construction per type category.
When it happens
Trigger: Passing a non-Nullable<T> type (e.g. int, string, or a custom struct not wrapped in Nullable<>) to NullableDescriptor's constructor, or having the descriptor factory route a type to NullableDescriptor incorrectly.
Common situations: Custom TypeDescriptorFactory registrations or reflection-based asset serialization scanning where type dispatch logic misclassifies a type as nullable; hand-constructed descriptors in unit tests.
Related errors
- Type [{0}] is not a primitive
- The associated asset type does not have a public parameterle
- The type of collection does not have a parameterless constru
- The type of dictionary does not have a parameterless constru
- Invalid assembly path. Doesn't contain directory information
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/959961e19581ce0c.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Reflection/TypeDescriptors/NullableDescriptor.cs:25
/// <summary>
/// Describes a descriptor for a nullable type <see cref="Nullable{T}"/>.
/// </summary>
public class NullableDescriptor : ObjectDescriptor
{
private static readonly List<IMemberDescriptor> EmptyMembers = [];
/// <summary>
/// Initializes a new instance of the <see cref="ObjectDescriptor" /> class.
/// </summary>
/// <param name="factory">The factory.</param>
/// <param name="type">The type.</param>
/// <exception cref="ArgumentException">Type [{0}] is not a primitive</exception>
public NullableDescriptor(ITypeDescriptorFactory factory, Type type, bool emitDefaultValues, IMemberNamingConvention namingConvention)
: base(factory, type, emitDefaultValues, namingConvention)
{
if (!IsNullable(type))
throw new ArgumentException("Type [{0}] is not a primitive");
UnderlyingType = Nullable.GetUnderlyingType(type)!;
}
public override DescriptorCategory Category => DescriptorCategory.Nullable;
/// <summary>
/// Gets the type underlying type T of the nullable <see cref="Nullable{T}"/>
/// </summary>
/// <value>The type of the element.</value>
public Type UnderlyingType { get; }
/// <summary>
/// Determines whether the specified type is nullable.
/// </summary>
/// <param name="type">The type.</param>
/// <returns><c>true</c> if the specified type is nullable; otherwise, <c>false</c>.</returns>
public static bool IsNullable(Type type)View on GitHub (pinned to 96fad776d2)