Skip to content

CHR0020: Constraint expression lambda must only access members

Expression lambdas passed to constraint builder methods (e.g. On<TEvent>(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.Constraints;
public class OrderPlaced { public string OrderId { get; set; } }
public class OrderConstraint : IConstraint
{
public void Define(IConstraintBuilder builder) =>
builder.Unique(u => u.On<OrderPlaced>(e => e.OrderId.ToLower())); // ❌ method call — never executed
}
using Cratis.Chronicle.Events.Constraints;
public class OrderPlaced { public string OrderId { get; set; } }
public class OrderConstraint : IConstraint
{
public void Define(IConstraintBuilder builder) =>
builder.Unique(u => u.On<OrderPlaced>(e => e.OrderId)); // ✅ simple member access
}

In Chronicle’s constraint builder, any parameter typed as Expression<Func<...>> is parsed at startup to extract a property name for the constraint rule—the lambda body is never executed at runtime. Writing method calls, arithmetic, conditional expressions, or similar executable code in such a lambda will be silently ignored, producing an incorrect or incomplete constraint definition.

The only valid lambda body is a direct property access, for example e => e.Email or e => e.OrderId.

If case-insensitive comparison is needed, use builder.Unique(u => u.On<OrderPlaced>(e => e.Email).IgnoreCasing()) instead of transforming the value in the lambda.

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