Skip to content

CHR0049: `[EventTypeGenerationFor<T>]` must reference a type marked with `[EventType]`

[EventTypeGenerationFor<T>] marks a record as a previous generation of the event type T represents. Chronicle resolves the shared event type id directly from T’s own [EventType] attribute — so T must carry [EventType] directly.

This is reported whenever T:

  • has no [EventType] attribute at all, or
  • is itself marked with [EventTypeGenerationFor<T>] instead — chaining generation markers is rejected for the same reason: there is still no [EventType] at the end of the chain to resolve an id from.

Error

using Cratis.Chronicle.Events;
public record Chr0049ViolationCustomerRegisteredV2(string FirstName, string LastName);
// Error CHR0049: 'Chr0049ViolationCustomerRegisteredV1' declares itself as a generation for
// 'Chr0049ViolationCustomerRegisteredV2', but 'Chr0049ViolationCustomerRegisteredV2' is not
// marked with [EventType].
[EventTypeGenerationFor<Chr0049ViolationCustomerRegisteredV2>(1)]
public record Chr0049ViolationCustomerRegisteredV1(string Name);

View C# snippet source on GitHub

using Cratis.Chronicle.Events;
[EventType("customer-registered", generation: 2)]
public record Chr0049FixCustomerRegisteredV2(string FirstName, string LastName);
[EventTypeGenerationFor<Chr0049FixCustomerRegisteredV2>(1)]
public record Chr0049FixCustomerRegisteredV1(string Name);

View C# snippet source on GitHub

[EventTypeGenerationFor<T>] exists so a previous-generation record never carries its own, independently-typed event type id — the id comes from T instead, so the two can never drift apart. That only works if T actually has an id to give: a type with no [EventType] attribute has none, and neither does a type that is itself only a generation marker.

Without this check, a record marked [EventTypeGenerationFor<T>] where T isn’t an event type compiles cleanly but fails only when the client connects to Chronicle, throwing EventTypeGenerationReferencesNonEventType at startup. This rule surfaces the same mistake at compile time instead.

  • CHR0050: [EventType] and [EventTypeGenerationFor<T>] cannot be combined — validates that a type is either the current event type or a previous generation, never both.
  • CHR0037: Event type migration generations must belong to one event type — validates that a migration’s [EventTypeGenerationFor<T>] points at the migration’s own upgrade type, once it already resolves to an event type.