MonoGame/MonoGame · error · NotImplementedException
Unhandled primitive type `{type.FullName}`!
Error message
Unhandled primitive type `{type.FullName}`! What it means
GetTypeSerializer falls back to the ReflectiveSerializer for unknown types, but reflection-based serialization is intentionally forbidden for CLR primitives. If a primitive numeric/pointer type has no registered ContentTypeSerializer, the lookup throws NotImplementedException rather than mis-serializing it by reflection.
Source
Thrown at MonoGame.Framework.Content.Pipeline/Serialization/Intermediate/IntermediateSerializer.cs:175
{
serializerType = serializerType.MakeGenericType(type.GetGenericArguments());
serializer = (ContentTypeSerializer)Activator.CreateInstance(serializerType)!;
}
else if (type.IsEnum)
{
serializer = new EnumSerializer(type);
}
else if (typeof(IList).IsAssignableFrom(type) && !GenericCollectionHelper.IsGenericCollectionType(type, true))
{
// Special handling for non-generic IList types. By the time we get here,
// generic collection types will already have been handled by one of the known serializers.
serializer = new NonGenericIListSerializer(type);
}
else
{
// The reflective serializer is not for primitive types!
if (type.IsPrimitive)
throw new NotImplementedException($"Unhandled primitive type `{type.FullName}`!");
// We still don't have a serializer then we
// fallback to the reflection based serializer.
serializer = new ReflectiveSerializer(type);
}
Debug.Assert(serializer.TargetType == type, "Target type mismatch!");
// We cache the serializer before we initialize it to
// avoid a stack overflow on recursive types.
_serializers.Add(type, serializer);
serializer.Initialize(this);
return serializer;
}
internal GenericCollectionHelper GetCollectionHelper(Type type)
{View on GitHub (pinned to 1d71bbd0ff)
Solutions
- Do not serialize native pointer/handle primitives; wrap them in a non-primitive type or exclude them with [ContentSerializerIgnore].
- Store the value as a serializable `long`/`ulong` and convert to IntPtr at use sites.
- Register a custom ContentTypeSerializer for the primitive type if serialization is genuinely required.
Example fix
// before
public class GpuResource
{
public IntPtr Handle { get; set; }
}
// after
public class GpuResource
{
public long HandleValue { get; set; }
[ContentSerializerIgnore]
public IntPtr Handle { get => (IntPtr)HandleValue; set => HandleValue = (long)value; }
} Defensive patterns
Strategy: type-guard
Validate before calling
// Reject serializable members whose primitive type has no registered serializer
var ptrTypes = typeof(T).GetFields()
.Where(f => f.FieldType.IsPrimitive && !typeof(bool).IsAssignableFrom(f.FieldType)
&& !new[] { typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int),
typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(char) }
.Contains(f.FieldType));
if (ptrTypes.Any())
throw new NotSupportedException("Unserializable primitive member: " + string.Join(", ", ptrTypes.Select(f => f.Name))); Type guard
static bool IsSerializablePrimitive(Type t) =>
!t.IsPrimitive || new[] { typeof(bool), typeof(byte), typeof(sbyte), typeof(short),
typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong),
typeof(float), typeof(double), typeof(char) }.Contains(t); Try / catch
try { IntermediateSerializer.Serialize(writer, value, path); }
catch (NotImplementedException ex) when (ex.Message.Contains("Unhandled primitive"))
{
// replace the IntPtr/nint member with a long, or mark it [ContentSerializerIgnore]
} Prevention
- Never expose IntPtr/UIntPtr/nint as serializable members; store as long/ulong.
- Run a reflection scan over pipeline data types for unhandled primitives.
- Unit-test round-trip for every serializable type.
When it happens
Trigger: A type graph containing a primitive type for which no explicit serializer is registered. In practice this is `IntPtr`/`UIntPtr`/`nint`/`nuint` (which report IsPrimitive == true in modern .NET) used as a serializable field/property, since int/float/double/etc. all have dedicated serializers.
Common situations: Adding a native-handle-sized field (`IntPtr handle`) to a pipeline-serializable class, or targeting a runtime where a previously-registered primitive serializer was removed.
Related errors
- You cannot deserialize an array into a getter-only property.
- Elements count in CurveKeyCollection is inncorect!
- Not have enough entries in space-separated list!
- Invalid type has been provided for GenericCollectionHelper:
- Missing shared resource "{fixup.Key}".
AI-assisted analysis of MonoGame/MonoGame@1d71bbd0ff (2026-08-13).
Data as JSON: /api/errors/3007507b14454fda.
Report an issue: GitHub.