Skip to content

CHR0019: Projection expression lambda must only access members

Expression lambdas passed to projection builder methods (e.g. Set(x => ...), To(e => ...), IdentifiedBy(x => ...), UsingKey(e => ...)) must only contain simple member access. They cannot contain method calls, arithmetic, conditional expressions, or any other executable code.

Error

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
public class Chr0019UserReadModel
{
public string Name { get; set; } = string.Empty;
}
[EventType]
public record Chr0019UserRegistered(string Name);
public class Chr0019UserProjection : IProjectionFor<Chr0019UserReadModel>
{
public void Define(IProjectionBuilderFor<Chr0019UserReadModel> builder) =>
builder.From<Chr0019UserRegistered>(_ => _
.Set(x => x.Name)
.To(e => e.Name.ToUpper())); // CHR0019: method call - never executed
}
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
public class Chr0019UserReadModelFixed
{
public string Name { get; set; } = string.Empty;
}
[EventType]
public record Chr0019UserRegisteredFixed(string Name);
public class Chr0019UserProjectionFixed : IProjectionFor<Chr0019UserReadModelFixed>
{
public void Define(IProjectionBuilderFor<Chr0019UserReadModelFixed> builder) =>
builder.From<Chr0019UserRegisteredFixed>(_ => _
.Set(x => x.Name)
.To(e => e.Name)); // Now valid - simple member access
}

In Chronicle’s projection builder, any parameter typed as Expression<Func<...>> is parsed at startup to extract a property path for the read-model mapping—the lambda body is never executed at runtime. Writing method calls, arithmetic (e.Count + 1), conditional expressions (e.Flag ? e.A : e.B), or similar executable code in such a lambda will be silently ignored, producing an incorrect or incomplete projection definition that is very difficult to debug.

The only valid lambda body is a direct property access chain, for example x => x.Property or x => x.Parent.Child.

  • CHR0016: Projection Define() must not contain imperative code
  • CHR0020: Constraint expression lambda must only access members