What happens
MetadataFile.Deserialize<T> (SourceGeneratorToolkit/MetadataFile.cs, lines 109-128) wraps JsonSerializer.Deserialize<T>(Text, DeserializeOptions) in a try that only catches System.Text.Json.JsonException (line 123). Per System.Text.Json's documented behavior, deserializing into a type with no compatible converter throws System.NotSupportedException, which is a distinct, sibling exception type — not caught here.
Confirmed by direct execution:
- An interface- or abstract-typed metadata model throws
NotSupportedException: Deserialization of interface or abstract types is not supported. Type 'IThing'.
- A metadata model with two ambiguous public constructors and no
[JsonConstructor] throws NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported.
Why it matters
This directly undermines the toolkit's own stated design guarantee (per CLAUDE.md): "A missing or malformed file always reports... swallowing an exception means malformed metadata silently generates something wrong / produces no diagnostic."
Concretely: a consuming repository models a metadata DTO with an interface-typed property (a natural choice for e.g. "one of several variant kinds"), or a record with two constructors and no [JsonConstructor]. As soon as any AdditionalFile has that shape, Deserialize<T> throws NotSupportedException, which propagates out of GeneratorBase<T>.Generate and out of the RegisterSourceOutput callback uncaught. The Roslyn driver catches this at its own top level and reports the generic CS8785 ("Generator failed to generate source... Exception was of type 'NotSupportedException'") instead of the toolkit's intended MetadataParseFailed diagnostic. For a multi-file generator, this also aborts processing of every other file in the same RegisterSourceOutput invocation, not just the offending one.
Suggested fix
Broaden the catch in Deserialize<T> to also catch NotSupportedException (and consider InvalidOperationException, which System.Text.Json also uses for some converter-configuration failures), reporting parseFailed with the exception's message the same way the existing JsonException branch does — so any deserialization failure degrades to the documented diagnostic instead of crashing the generator.
Acceptance criteria
- An
AdditionalFile that deserializes to an interface/abstract type, or to a type with ambiguous constructors, produces the toolkit's MetadataParseFailed-style diagnostic instead of a generator crash / CS8785.
- Other declared files in the same generator invocation still process normally when one file fails to deserialize this way.
What happens
MetadataFile.Deserialize<T>(SourceGeneratorToolkit/MetadataFile.cs, lines 109-128) wrapsJsonSerializer.Deserialize<T>(Text, DeserializeOptions)in atrythat only catchesSystem.Text.Json.JsonException(line 123). PerSystem.Text.Json's documented behavior, deserializing into a type with no compatible converter throwsSystem.NotSupportedException, which is a distinct, sibling exception type — not caught here.Confirmed by direct execution:
NotSupportedException: Deserialization of interface or abstract types is not supported. Type 'IThing'.[JsonConstructor]throwsNotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported.Why it matters
This directly undermines the toolkit's own stated design guarantee (per
CLAUDE.md): "A missing or malformed file always reports... swallowing an exception means malformed metadata silently generates something wrong / produces no diagnostic."Concretely: a consuming repository models a metadata DTO with an interface-typed property (a natural choice for e.g. "one of several variant kinds"), or a record with two constructors and no
[JsonConstructor]. As soon as anyAdditionalFilehas that shape,Deserialize<T>throwsNotSupportedException, which propagates out ofGeneratorBase<T>.Generateand out of theRegisterSourceOutputcallback uncaught. The Roslyn driver catches this at its own top level and reports the genericCS8785("Generator failed to generate source... Exception was of type 'NotSupportedException'") instead of the toolkit's intendedMetadataParseFaileddiagnostic. For a multi-file generator, this also aborts processing of every other file in the sameRegisterSourceOutputinvocation, not just the offending one.Suggested fix
Broaden the catch in
Deserialize<T>to also catchNotSupportedException(and considerInvalidOperationException, whichSystem.Text.Jsonalso uses for some converter-configuration failures), reportingparseFailedwith the exception's message the same way the existingJsonExceptionbranch does — so any deserialization failure degrades to the documented diagnostic instead of crashing the generator.Acceptance criteria
AdditionalFilethat deserializes to an interface/abstract type, or to a type with ambiguous constructors, produces the toolkit'sMetadataParseFailed-style diagnostic instead of a generator crash /CS8785.