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

[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.

The same analyzer class also reports CHR0050 (EventTypeGenerationForCannotCombineWithEventType, Error) when a type carries both [EventType] and [EventTypeGenerationFor<T>] at once. A type is either the current generation or a previous one — never both — and combining them throws EventTypeGenerationForCannotBeCombinedWithEventType at runtime for the same reason this rule’s violation does: Chronicle can no longer tell which attribute owns the id.

  • 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.