stride3d/stride · error · InvalidOperationException
The generic argument of this class must be the type being…
Error message
The generic argument of this class must be the type being implemented.
What it means
ValueConverterBase<T> enforces the CRTP pattern: the generic argument T must be the concrete class deriving from it. The protected constructor compares GetType() with typeof(T) and throws InvalidOperationException when they differ, ensuring the singleton ProvideValue pattern (which news up a T) returns an instance of the actual converter class.
Solutions
- Set the generic argument to the class being declared: class MyConverter : ValueConverterBase<MyConverter>
- If you need a shared intermediate base, make it abstract and have each leaf pass itself: abstract class ConverterBase : ValueConverterBase<ConverterBase> is invalid — each concrete class must use its own type
- Verify every class deriving from ValueConverterBase<T> passes its own name as T
Example fix
// before
class MyConverter : ValueConverterBase<XOrMultiConverter> { ... }
// after
class MyConverter : ValueConverterBase<MyConverter> { ... } Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof(T) != GetType()) throw new InvalidOperationException("T must equal the implementing type"); Type guard
bool IsValidConverterBase<T>(object o) => o.GetType() == typeof(T);
Try / catch
try { var c = new MyConverter(); } catch (InvalidOperationException ex) when (ex.Message.Contains("generic argument")) { /* fix T */ } Prevention
- Always pass the declaring class itself as T
- Avoid intermediate non-abstract generic bases that hard-code T
- Review converter declarations after renames
When it happens
Trigger: Declaring a converter like class MyConverter : ValueConverterBase<SomeOtherConverter>, or subclassing an intermediate base without re-pointing T to the leaf class.
Common situations: Copy-pasting a converter declaration and forgetting to update the generic argument; creating an intermediate abstract base class that keeps the wrong T; renaming a converter class without updating the generic parameter.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- The generic argument of this class must be the type being…
- Converter is not null but previous Converter was null
- Converter is null but following Converter is not null
- Requested conversion is not supported.
- The given value must implement IEnumerable
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/966e26db2f02efd1.
Report an issue: GitHub.
Appendix: source
Thrown at sources/presentation/Stride.Core.Presentation.Wpf/ValueConverters/ValueConverterBase.cs:25
using Stride.Core.Annotations;
namespace Stride.Core.Presentation.ValueConverters
{
/// <summary>
/// An abstract class for implementations of <see cref="IValueConverter"/> that supports markup extensions.
/// </summary>
/// <typeparam name="T">The type of <see cref="IValueConverter"/> being implemented.</typeparam>
public abstract class ValueConverterBase<T> : MarkupExtension, IValueConverter where T : class, IValueConverter, new()
{
private static T valueConverterInstance;
/// <summary>
/// Initializes a new instance of the <see cref="ValueConverterBase{T}"/> class.
/// </summary>
/// <exception cref="InvalidOperationException">The generic argument does not match the type of the implementation of this class.</exception>
protected ValueConverterBase()
{
if (GetType() != typeof(T)) throw new InvalidOperationException("The generic argument of this class must be the type being implemented.");
}
/// <inheritdoc/>
public override object ProvideValue(IServiceProvider serviceProvider)
{
return valueConverterInstance ?? (valueConverterInstance = new T());
}
/// <inheritdoc/>
public abstract object Convert(object value, [NotNull] Type targetType, object parameter, CultureInfo culture);
/// <inheritdoc/>
public abstract object ConvertBack(object value, [NotNull] Type targetType, object parameter, CultureInfo culture);
}
}
View on GitHub (pinned to 96fad776d2)