WHIZ400: Invalid Type Argument for ILensQuery¶
Verified by tests
LensQueryTypeArgumentAnalyzerTests — library CI run #31657041675 (2026-08-13)
Severity: Error Category: Type Safety
Description¶
This error is reported when calling Query<T>() or GetByIdAsync<T>() on a multi-generic ILensQuery<T1, T2, ...> with a type argument that is not one of the interface's registered type parameters.
The analyzer catches this error at compile time, preventing runtime ArgumentException errors.
Diagnostic Message¶
Common Causes¶
- Wrong type argument - Using a type that wasn't registered with the multi-generic interface
- Copy-paste error - Copying code from a resolver using different perspective types
- Refactoring mistake - Changed the interface type parameters but not the query calls
How to Fix¶
Ensure the type argument to Query<T>() or GetByIdAsync<T>() is one of the interface's type parameters.
Before (causes WHIZ400)¶
Before (causes WHIZ400)
public class OrderResolver {
public async Task<ProductDto> GetProduct(
[Service] ILensQuery<Order, Customer> query, // Only Order and Customer
Guid productId,
CancellationToken ct) {
// WHIZ400: Product is not valid for ILensQuery<Order, Customer>
return await query.GetByIdAsync<Product>(productId, ct);
}
}
Fix Option 1: Use the correct interface¶
Fix Option 1: Use the correct interface
public class OrderResolver {
public async Task<ProductDto> GetProduct(
[Service] ILensQuery<Order, Customer, Product> query, // Added Product
Guid productId,
CancellationToken ct) {
// OK - Product is T3
return await query.GetByIdAsync<Product>(productId, ct);
}
}
Fix Option 2: Use separate single-generic query¶
Fix Option 2: Use separate single-generic query
public class OrderResolver {
public async Task<ProductDto> GetProduct(
[Service] ILensQuery<Product> productQuery, // Separate query for Product
Guid productId,
CancellationToken ct) {
return await productQuery.GetByIdAsync(productId, ct);
}
}
Valid Usage Examples¶
Valid Usage Examples
// ILensQuery<Order, Customer>
query.Query<Order>(); // OK - T1
query.Query<Customer>(); // OK - T2
// ILensQuery<Order, Customer, Product>
query.Query<Order>(); // OK - T1
query.Query<Customer>(); // OK - T2
query.Query<Product>(); // OK - T3
query.GetByIdAsync<Order>(id); // OK
query.GetByIdAsync<Customer>(id); // OK
query.GetByIdAsync<Product>(id); // OK
Suppressing This Diagnostic¶
In rare cases where you intentionally want to suppress this error (e.g., testing runtime exception behavior), use pragma suppression:
Suppressing This Diagnostic
#pragma warning disable WHIZ400 // Intentional invalid type for testing
var result = query.Query<InvalidType>();
#pragma warning restore WHIZ400
Why This Matters¶
Without compile-time validation, invalid type arguments would cause runtime ArgumentException:
The WHIZ400 analyzer catches these errors during compilation, providing immediate feedback in your IDE and preventing runtime failures.
Runtime Behavior¶
Even without the analyzer, the runtime implementation validates type arguments. Multi-generic lens queries delegate to MultiModelScopedAccess<T1, T2, ...>, which type-checks the argument against each registered type parameter:
Runtime Behavior
// MultiModelScopedAccess<T1, T2> (2-model case)
public IQueryable<PerspectiveRow<T>> Query<T>() where T : class {
if (typeof(T) == typeof(T1)) {
return (IQueryable<PerspectiveRow<T>>)(object)MultiModelScopeHelper.GetQuery<T1>(context, _filterInfo);
}
if (typeof(T) == typeof(T2)) {
return (IQueryable<PerspectiveRow<T>>)(object)MultiModelScopeHelper.GetQuery<T2>(context, _filterInfo);
}
throw new ArgumentException($"Type '{typeof(T).Name}' is not valid. Valid types: {typeof(T1).Name}, {typeof(T2).Name}");
}
GetByIdAsync<T>() performs the same type check and throws ArgumentException with Type '{T}' is not valid. for an unregistered type.
AOT Compatibility¶
The analyzer and runtime validation are both AOT-compatible:
typeof(T) == typeof(T1)comparisons are compile-time constants- No reflection used at runtime
- Source-generated analyzer runs during compilation
See Also¶
- Multi-Model Queries - Using multi-generic ILensQuery for LINQ joins
- Lens Query Factory - DbContext sharing patterns