---
title: 'CHR0051: Reducer current read model parameter must be nullable'
---

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

## Rule Description

Chronicle passes `null` as the current read model for the event that brings an instance into existence, so a reducer method cannot promise the parameter is never null. Declare the parameter as nullable and handle the null case as the creation of the instance.

## Severity

Warning

## Example

### Violation

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

```csharp
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reducers;

public record Chr0051ViolationBookStatus(string Title, bool IsAvailable);

[EventType("book-added")]
public record Chr0051ViolationBookAdded(string Title);

public class Chr0051ViolationBookStatusReducer : IReducerFor<Chr0051ViolationBookStatus>
{
    // Warning CHR0051: Reducer method 'Reduce' declares its current read model parameter
    // as 'Chr0051ViolationBookStatus' rather than 'Chr0051ViolationBookStatus?'
    public Chr0051ViolationBookStatus Reduce(Chr0051ViolationBookAdded @event, Chr0051ViolationBookStatus current, EventContext context) =>
        new(@event.Title, true);
}
```

</TabItem>
</Tabs>

### Fix

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

```csharp
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reducers;

public record Chr0051FixBookStatus(string Title, bool IsAvailable);

[EventType("book-added")]
public record Chr0051FixBookAdded(string Title);

public class Chr0051FixBookStatusReducer : IReducerFor<Chr0051FixBookStatus>
{
    // The current read model parameter is nullable, handling creation correctly.
    public Chr0051FixBookStatus Reduce(Chr0051FixBookAdded @event, Chr0051FixBookStatus? current, EventContext context) =>
        current ?? new(@event.Title, true);
}
```

</TabItem>
</Tabs>

## Why This Rule Exists

A reducer's job is to fold an event and the current read model state into the next state. When an event is the **first** for a given event source, there is no current state — Chronicle passes `null` for the `current` parameter. A reducer method that declares `current` as non-nullable makes a promise it cannot keep, because the very first event for an instance will pass `null`.

In a `#nullable disable` context, the annotation carries no claim at all, so Chronicle keeps dispatching to those methods without complaint. This rule fires only when a method makes an **explicit non-nullable annotation** — the broken promise.

Declare `current` as nullable and handle the `null` case — typically by creating the initial instance — to make the reducer correct for both the first event and every subsequent one.

## Related Rules

- [CHR0006](/chronicle/code-analysis/chr0006/): Reducer method signature must match allowed signatures — validates the overall shape of a reducer method.
- [CHR0036](/chronicle/code-analysis/chr0036/): Reducer must not have mutable state — ensures reducers remain stateless and replay-safe.
