ruvnet/ruflo · warning
Too many events to replay (${events.length}). Consider creat
Error message
Too many events to replay (${events.length}). Consider creating a snapshot. What it means
StateReconstructor refuses to rebuild an aggregate when the number of events to apply after the latest snapshot exceeds options.maxEventsToReplay. Replay cost grows linearly with event count, so the guard stops expensive rebuilds and points you at snapshotting: with useSnapshots enabled and a reasonable snapshotInterval, rehydration starts from a recent snapshot and the replay count stays small. It typically fires for long-lived aggregates with no snapshot yet or a snapshot interval larger than the replay ceiling.
Source
Thrown at v3/@claude-flow/shared/src/events/state-reconstructor.ts:76
factory: (id: string) => T
): Promise<T> {
const aggregate = factory(aggregateId);
// Try to load from snapshot first
if (this.options.useSnapshots) {
const snapshot = await this.eventStore.getSnapshot(aggregateId);
if (snapshot) {
this.applySnapshot(aggregate, snapshot);
}
}
// Get events after snapshot version (or all if no snapshot)
const events = await this.eventStore.getEvents(aggregateId, aggregate.version + 1);
// Apply events
for (const event of events) {
if (events.length > this.options.maxEventsToReplay) {
throw new Error(`Too many events to replay (${events.length}). Consider creating a snapshot.`);
}
aggregate.apply(event);
}
// Create snapshot if interval reached
if (this.options.useSnapshots && aggregate.version % this.options.snapshotInterval === 0) {
await this.createSnapshot(aggregate);
}
return aggregate;
}
/**
* Reconstruct state at a specific point in time
*/
async reconstructAtTime<T extends AggregateRoot>(
aggregateId: string,View on GitHub (pinned to fa13ee4ad6)
Solutions
- Create a snapshot for the affected aggregate (createSnapshot / enable useSnapshots) so future rehydrations start from a recent version
- Lower options.snapshotInterval so snapshots are taken more frequently than maxEventsToReplay events accumulate
- If the hardware genuinely supports it, raise options.maxEventsToReplay deliberately as a tuning decision — then snapshot soon after
Example fix
// before
const recon = new StateReconstructor(store, factory, {
useSnapshots: false,
maxEventsToReplay: 1000,
});
await recon.rebuild(orderId); // long history -> throws
// after
const recon = new StateReconstructor(store, factory, {
useSnapshots: true,
snapshotInterval: 500,
maxEventsToReplay: 1000,
});
await recon.rebuild(orderId); // snapshots keep replay under the limit Defensive patterns
Strategy: fallback
Validate before calling
const recon = new StateReconstructor(eventStore, aggregateFactory, {
useSnapshots: true,
snapshotInterval: 500,
maxEventsToReplay: 1000,
});
// keep snapshotInterval well below maxEventsToReplay so this never trips Try / catch
try {
aggregate = await recon.rebuild(aggregateId);
} catch (e) {
if (e instanceof Error && e.message.includes('Too many events to replay')) {
// fallback: rebuild with a raised ceiling, snapshot immediately, then restore the normal limit
const tolerant = new StateReconstructor(eventStore, aggregateFactory, {
useSnapshots: true,
snapshotInterval: 100,
maxEventsToReplay: Number.MAX_SAFE_INTEGER,
});
aggregate = await tolerant.rebuild(aggregateId);
} else throw e;
} Prevention
- Enable useSnapshots and keep snapshotInterval far below maxEventsToReplay
- Snapshot high-write aggregates on a schedule, not just on version-interval
- Monitor per-aggregate event counts so the ceiling is raised deliberately, not discovered in production
When it happens
Trigger: Rehydrating an aggregate whose post-snapshot event count exceeds maxEventsToReplay; useSnapshots disabled in StateReconstructorOptions; snapshotInterval set so high (or event volume so bursty) that more than maxEventsToReplay events accumulate between snapshots; first rehydrate of an old aggregate created before snapshots existed.
Common situations: High-write event-sourced aggregates with sparse snapshots; snapshots turned off for simplicity then hitting the ceiling as history grows; bulk rehydration jobs (rebuilding all aggregates) tripping the limit on the oldest ones.
Related errors
- [RvfEventLog] Invalid file header in ${filePath}
- Concurrent write detected on aggregate '${aggregateId}'. Res
- EventStore not initialized. Call initialize() first.
- Event must have a valid aggregateId string
- Event must have a valid type string
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/4184efd0ca7cb10c.
Report an issue: GitHub.