abpframework/abp · error · AbpException

ChangeTypePrimitiveExtended<TProperty> does not support non-

Error message

ChangeTypePrimitiveExtended<TProperty> does not support non-primitive types. Use non-generic GetProperty method and handle type casting manually.

What it means

Thrown by TypeHelper.ChangeTypePrimitiveExtended<TProperty> when TProperty is not a primitive-extended type (primitives, Guid, enums, and their nullables). The method refuses to convert complex/object types and points you to the non-generic GetProperty path. It is an AbpException.

Source

Thrown at framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs:112

            if (IsNullable(conversionType))
            {
                conversionType = conversionType.GetFirstGenericArgumentIfNullable();
            }

            if (conversionType == typeof(Guid))
            {
                return (TProperty)TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString()!)!;
            }

            if (conversionType.IsEnum)
            {
                return (TProperty)Enum.Parse(conversionType, value.ToString()!);
            }

            return (TProperty)Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
        }

        throw new AbpException("ChangeTypePrimitiveExtended<TProperty> does not support non-primitive types. Use non-generic GetProperty method and handle type casting manually.");
    }

    public static bool IsNullable(Type type)
    {
        return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

    public static bool IsNullableEnum(Type type)
    {
        return type.IsGenericType &&
               type.GetGenericTypeDefinition() == typeof(Nullable<>) &&
               type.GenericTypeArguments.Length == 1 &&
               type.GenericTypeArguments[0].IsEnum;
    }

    public static Type GetFirstGenericArgumentIfNullable(this Type t)
    {
        if (t.GetGenericArguments().Length > 0 && t.GetGenericTypeDefinition() == typeof(Nullable<>))

View on GitHub (pinned to 7ed43b1931)

Solutions

  1. Use the non-generic GetProperty variant and perform the cast/deserialization manually (e.g. JsonSerializer.Deserialize).
  2. Restrict TProperty to primitive-extended types; decompose the complex property into primitives.
  3. If you wrote the caller, gate on TypeHelper.IsPrimitiveExtended(typeof(TProperty)) before invoking.
  4. Deserialize complex values to JSON first, then parse them into the target type.

Example fix

// before
var obj = TypeHelper.ChangeTypePrimitiveExtended<MyPoco>(raw);

// after
var obj = JsonSerializer.Deserialize<MyPoco>(raw.ToString()!);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!TypeHelper.IsPrimitiveExtended(typeof(TProperty), includeEnums: true))
    throw new InvalidOperationException("Use non-generic GetProperty for complex types");

var v = TypeHelper.ChangeTypePrimitiveExtended<TProperty>(raw);

Type guard

static bool IsPrimitiveExtended<T>()
    => TypeHelper.IsPrimitiveExtended(typeof(T), includeEnums: true);

Try / catch

try { var v = TypeHelper.ChangeTypePrimitiveExtended<TProperty>(raw); }
catch (AbpException ex) when (ex.Message.Contains("non-primitive"))
{
    // fall back to manual deserialization
    obj = JsonSerializer.Deserialize<TProperty>(raw.ToString()!);
}

Prevention

When it happens

Trigger: Calling ChangeTypePrimitiveExtended<SomeComplexType>(value) where SomeComplexType is a class/struct that is not in the primitive-extended set.

Common situations: Binding a setting/configuration value to a complex POCO via the generic helper, deserializing from a dictionary into a non-primitive property, or a generic property accessor that assumes primitives but receives an object type.

Related errors


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/61947b97b90e056a. Report an issue: GitHub.