CHR0020: Constraint expression lambda must only access members
Rule Description
Section titled “Rule Description”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.
Severity
Section titled “Severity”Error
Example
Section titled “Example”Violation
Section titled “Violation”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}Why This Rule Exists
Section titled “Why This Rule Exists”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.