Skip to content

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

  1. Using non-generic collection interfaces - IEnumerable, IList, ICollection instead of their generic counterparts
  2. Custom non-generic interfaces - User-defined interfaces without type parameters
  3. 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:

  1. Type Discovery - Non-generic interfaces hide the actual runtime type
  2. AOT Compilation - Cannot generate serialization code for unknown types
  3. Runtime Errors - Would cause serialization failures in production

Custom Interfaces

For custom interfaces, either:

  1. Make them generic with type parameters
  2. Use concrete types instead
  3. Use an abstract base class instead of an interface — abstract classes are not flagged, and Whizbang's MessageJsonContextGenerator automatically 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)

[*.cs]
dotnet_diagnostic.WHIZ062.severity = none
  • WHIZ060 - Property uses object type
  • WHIZ061 - Property uses dynamic type
  • WHIZ063 - Nested type contains non-serializable property
  • Serializable Property Analyzer - Analyzer overview

See Also

  • AOT Compatibility - AOT design principles
  • Messages - ICommand and IEvent documentation