---
title: 'CHR0040: Several [SetFromContext] for the same event type on one member'
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

## Rule Description

One read model member carries more than one `[SetFromContext<TEvent>]` for the *same* event type. They write the same property in the projection definition, so only the last declared is kept — the earlier capture is silently discarded, with no build, registration, or runtime signal.

Allowing multiple `[SetFromContext]` on one member is deliberate and load-bearing: a property capturing context from several *different* event types is exactly what the attribute is for, and that use never triggers this rule. Two for the same event type is different — a single value cannot hold two context values under any configuration, naming policy, or event shape.

Keep the capture that was intended, or move the other onto its own property.

Every spelling of "one member" is covered. On a positional record the constructor parameter and the property generated from it are two distinct symbols — `[property:]` is the only way to reach the second — and both write the same key into the same event type's definition. A duplicate split across the two spellings is reported exactly as one placed twice on a single symbol.

## Severity

Warning

## Example

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Keys;
using Cratis.Chronicle.Projections.ModelBound;

[EventType]
public record Chr0040OrderPlaced(decimal Amount);

// Warning CHR0040: 'PlacedAt' carries more than one [SetFromContext<Chr0040OrderPlaced>],
// and they map to the same property - only the last declared is kept. The CorrelationId
// capture is silently dropped: a single member cannot hold both context values. Move it
// onto its own property instead.
[FromEvent<Chr0040OrderPlaced>]
public record Chr0040Order(
    [Key] Guid Id,
    decimal Amount,
    [SetFromContext<Chr0040OrderPlaced>(nameof(EventContext.CorrelationId))]
    [SetFromContext<Chr0040OrderPlaced>(nameof(EventContext.Occurred))]
    DateTimeOffset PlacedAt);
```

</TabItem>
</Tabs>

## Why This Rule Exists

The failure is maximally quiet. The property *is* populated — with the other context value — so nothing is null, nothing throws, and a spec asserting the property has a value stays green. It reads as a projection written wrong, and the natural way to debug it — re-reading the attributes and finding both present and correctly spelled — confirms the wrong conclusion.

This is a warning where the neighboring AutoMap collision rule ([CHR0025](/chronicle/code-analysis/chr0025/)) deliberately only informs, and the difference is the point: that collision has two legitimate resolutions and only the author knows which was meant, while here there is no second reading to defer to.

## Related Rules

- [CHR0025: Explicitly sourced read model property may be overwritten by AutoMap](/chronicle/code-analysis/chr0025/) — the sibling collision that *is* sometimes intended, and is therefore only informational.
- [CHR0042: A joined property is also written locally](/chronicle/code-analysis/chr0042/) — another shape where two writes to one property silently resolve to one winner.
