abpframework/abp · error · ArgumentException
{parameterName} (type of {type.AssemblyQualifiedName}) shoul
Error message
{parameterName} (type of {type.AssemblyQualifiedName}) should be assignable to the {typeof(TBaseType).GetFullNameWithAssemblyName()}! What it means
Thrown by Check.AssignableTo<TBaseType>(Type, string) when the supplied type is not assignable to TBaseType (i.e. it neither is, nor implements/derives from, the expected base type). The message includes both the offending type's AssemblyQualifiedName and the expected type's full name so mismatches are obvious.
Source
Thrown at framework/src/Volo.Abp.Core/Volo/Abp/Check.cs:135
{
if (value == null || value.Count <= 0)
{
throw new ArgumentException(parameterName + " can not be null or empty!", parameterName);
}
return value;
}
[ContractAnnotation("type:null => halt")]
public static Type AssignableTo<TBaseType>(
Type type,
[InvokerParameterName][NotNull] string parameterName)
{
NotNull(type, parameterName);
if (!type.IsAssignableTo<TBaseType>())
{
throw new ArgumentException($"{parameterName} (type of {type.AssemblyQualifiedName}) should be assignable to the {typeof(TBaseType).GetFullNameWithAssemblyName()}!");
}
return type;
}
public static string? Length(
string? value,
[InvokerParameterName][NotNull] string parameterName,
int maxLength,
int minLength = 0)
{
if (minLength > 0)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException(parameterName + " can not be null or empty!", parameterName);
}
View on GitHub (pinned to 7ed43b1931)
Solutions
- Compare the two type names in the exception message: make the offending type implement or derive from the expected base type.
- Verify the assembly actually loaded is the one you compiled against (check the AssemblyQualifiedName, not just the FullName) to catch version/redirect mismatches.
- If multiple candidates are possible, use typeof(...) explicitly as the generic argument rather than relying on inference.
- Add a unit test asserting type.IsAssignableTo<TBaseType>() to catch regressions after refactors.
Example fix
// before
public class MyHandler { } // missing interface
Check.AssignableTo<IEventHandler>(typeof(MyHandler), nameof(handlerType));
// after
public class MyHandler : IEventHandler { }
Check.AssignableTo<IEventHandler>(typeof(MyHandler), nameof(handlerType)); Defensive patterns
Strategy: type-guard
Validate before calling
// Verify assignability before calling Check.AssignableTo
if (!typeof(MyHandler).IsAssignableTo<IEventHandler>())
throw new InvalidOperationException($"{typeof(MyHandler)} is not an IEventHandler"); Type guard
static bool IsA<TBase>(Type t) => t.IsAssignableTo<TBase>();
// usage: if (IsA<IEventHandler>(candidateType)) { ... } Prevention
- Add a unit test asserting candidateType.IsAssignableTo<TBase>() for every convention-registered type.
- Pin plugin assemblies with a test that loads them and checks assignability, to catch version skew.
- Prefer explicit typeof(...) generic arguments over inference when registering reflected types.
When it happens
Trigger: Calling Check.AssignableTo<IMyService>(concreteType, nameof(concreteType)) where concreteType does not implement IMyService. Common in ABP module/contributor code that reflects over assemblies or plugin types, and in typed registration helpers that must verify a candidate type fits a contract.
Common situations: Registering a plugin/convention type that was refactored and lost an interface; passing a base type where a derived type is required; version skew where an assembly was swapped and a type no longer implements the expected interface; wrong generic argument inferred by the compiler.
Related errors
- {parameterName} is equal to zero
- {parameterName} is less than zero
- {parameterName} is out of range min: {minimumValue} - max: {
- Job args types cannot contain null.
- Given tenant doesn't exist: {0}
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/4ea2bf11bded2008.
Report an issue: GitHub.