WHIZ062: Property Uses Non-Serializable Interface Type¶
Verified by tests
SerializablePropertyAnalyzerTests — library CI run #31657041675 (2026-08-13)
Severity: Error Category: Serialization Validation
Description¶
This error occurs when a property on a public ICommand, IEvent, or [WhizbangSerializable] type uses a non-generic interface type. Non-generic interfaces cannot be serialized with System.Text.Json source generation because the concrete type is not known at compile time.
Diagnostic Message¶
Property 'Items' on 'CreateOrderCommand' uses interface type 'System.Collections.IEnumerable' which cannot be serialized for AOT. Use a concrete type or generic collection instead.
Common Causes¶
- Using non-generic collection interfaces -
IEnumerable,IList,ICollectioninstead of their generic counterparts - Custom non-generic interfaces - User-defined interfaces without type parameters
- Legacy API compatibility - Interfacing with older APIs that use non-generic types
How to Fix¶
Replace non-generic interfaces with generic versions or concrete types:
Before (causes WHIZ062)¶
Before (causes WHIZ062)
public record CreateOrderCommand : ICommand {
public Guid OrderId { get; init; }
public IEnumerable Items { get; init; } // WHIZ062
public IList LineItems { get; init; } // WHIZ062
public ICollection Tags { get; init; } // WHIZ062
}
After (error resolved)¶
After (error resolved)
public record CreateOrderCommand : ICommand {
public Guid OrderId { get; init; }
public IEnumerable<OrderItem> Items { get; init; } = [];
public IList<LineItem> LineItems { get; init; } = [];
public ICollection<string> Tags { get; init; } = [];
}
Generic Interfaces Are Allowed¶
Generic interfaces with type parameters are serializable:
Generic Interfaces Are Allowed
public record ValidCommand : ICommand {
// All OK - generic interfaces
public IEnumerable<string> Tags { get; init; } = [];
public IReadOnlyList<OrderItem> Items { get; init; } = [];
public IDictionary<string, string> Metadata { get; init; } = new Dictionary<string, string>();
public IReadOnlyCollection<Guid> Ids { get; init; } = [];
}
The analyzer does not inspect type arguments of generic interfaces, so IDictionary<string, object> would also pass — but its object values would still fail AOT serialization at runtime. Keep type arguments concrete.
Why This Matters¶
System.Text.Json with source generation requires knowing concrete types at compile time:
- Type Discovery - Non-generic interfaces hide the actual runtime type
- AOT Compilation - Cannot generate serialization code for unknown types
- Runtime Errors - Would cause serialization failures in production
Custom Interfaces¶
For custom interfaces, either:
- Make them generic with type parameters
- Use concrete types instead
- Use an abstract base class instead of an interface — abstract classes are not flagged, and Whizbang's
MessageJsonContextGeneratorautomatically registers derived types for polymorphic serialization (reported as WHIZ071)
Example: Custom Interface Fix¶
Example: Custom Interface Fix
// Before - non-generic interface
public interface IPaymentMethod { }
public record ProcessPaymentCommand : ICommand {
public IPaymentMethod Payment { get; init; } // WHIZ062
}
// After - use concrete type or generic wrapper
public record ProcessPaymentCommand : ICommand {
public PaymentInfo Payment { get; init; } // OK - concrete type
}
Suppressing This Diagnostic¶
If you must use a non-generic interface:
Suppressing This Diagnostic
#pragma warning disable WHIZ062
public IEnumerable LegacyItems { get; init; }
#pragma warning restore WHIZ062
Or project-wide via .editorconfig (NoWarn does not suppress Error-severity diagnostics):
Suppressing This Diagnostic (2)
Related Diagnostics¶
- WHIZ060 - Property uses
objecttype - WHIZ061 - Property uses
dynamictype - WHIZ063 - Nested type contains non-serializable property
- Serializable Property Analyzer - Analyzer overview
See Also¶
- AOT Compatibility - AOT design principles
- Messages - ICommand and IEvent documentation