Skip to content

Fix invalid generated class name for batched (array) message types (GH-3399)#3406

Merged
jeremydmiller merged 1 commit into
mainfrom
fix-3399-codegen-array-name
Jul 13, 2026
Merged

Fix invalid generated class name for batched (array) message types (GH-3399)#3406
jeremydmiller merged 1 commit into
mainfrom
fix-3399-codegen-array-name

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3399. For 6.18.0. Reported by @outofrange-consulting — thank you, the repro was exact. (Supersedes #3405, which had the wrong commit pushed to its branch from a shared working tree; the fix itself is unchanged.)

Startup-fatal

HandlerGraph.cs:389-390 composed the generated class name straight off the message type when disambiguating duplicate TypeNames:

chain.TypeName =
    $"{chain.MessageType.ToSuffixedTypeName("")}_{chain.HandlerCalls().First().HandlerType.ToSuffixedTypeName("Handler")}";

ToSuffixedTypeName strips generic arity but does nothing about arrays. Since BatchMessagesOf<T>() makes T[] the handled message type, that emitted:

ItemDeleted[]1177234954_TelemetryHandlerHandler550305999

— not a legal C# identifier → CS1514/CS1513/CS1001the application dies at startup.

Tellingly, HandlerChain.cs:69/85 and SagaChain.cs:166 already guarded this with an ad-hoc .Replace("[]", "Array"). The disambiguation path was the one site that didn't.

The trigger — and why our tests missed it

Two conditions were obvious. A third was not, and it is the reason this went unnoticed:

  1. MultipleHandlerBehavior.Separated, and
  2. a handler class handling two message types, one of them batched, and
  3. each of those two message types must also have a second handler.

HandlerChain.cs:114 gates sticky-chain creation on grouping.Count() > 1. Without a second handler there are no sticky chains, so the disambiguation branch never runs — condition (3) is load-bearing. With it, the shared handler class gets two sticky chains both named off the handler type (HandlerChain.cs:85), the TypeNames collide, and the duplicate path fires.

That pins the coverage gap exactly: separated_batch_routing.cs and batching_with_separated_handlers.cs do exercise Separated + batching, but every handler class in them handles exactly one message type — so sticky TypeNames never collide.

Not a 6.17.x regression; the disambiguation path is old.

Fix

Centralized the scattered .Replace("[]", "Array") idiom into HandlerChain.GeneratedTypeNameFor(Type, string), reusing the existing JasperFx.Core.Reflection.Sanitize() helper rather than hand-rolling one, and applied it at the disambiguation site plus the three pre-existing sites that had each solved it locally.

Collisions remain impossible: ToSuffixedTypeName appends a hash of the type's full name, and T vs T[] differ there. The test asserts distinctness, not merely that the name is legal.

Verification

  • Red first: both new tests failed with the reporter's exact Compilation failures! CS1514/CS1513/CS1001, then green.
  • Full CoreTests 1923 passed, 0 failed (net9.0).
  • Batching / saga / separated filter: 183 passed, 0 failed.
  • Full wolverine.slnx Release build: 0 warnings, 0 errors.

🤖 Generated with Claude Code

…H-3399)

The duplicate-TypeName disambiguation in HandlerGraph rebuilt the generated
handler class name straight off the message type. For a batched message --
BatchMessagesOf<T>() makes T[] the handled message type -- that emitted a
name like "ItemDeleted[]1177234954_TelemetryHandlerHandler550305999", which
is not a legal C# identifier, so codegen died with CS1514/CS1513/CS1001 and
took the app down at startup.

Centralize the codegen-safe name composition that HandlerChain already did
ad hoc (Replace("[]", "Array")) into HandlerChain.GeneratedTypeNameFor, add
JasperFx's Sanitize() for any other punctuation, and use it on the
disambiguation path in HandlerGraph.

Reported by @outofrange-consulting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit 37fc393 into main Jul 13, 2026
26 checks passed
This was referenced Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codegen emits an invalid class name for array (batched) message types when duplicate handler TypeNames are disambiguated

1 participant