aeron-io/aeron · critical · ClusterException

missing begin snapshot

Error message

missing begin snapshot

What it means

An END snapshot marker was received while no BEGIN marker had been seen, meaning the stream started mid-snapshot. The loader requires the full marker protocol (BEGIN ... sections ... END); an END without a matching BEGIN means snapshot data is incomplete and cannot be trusted, so it aborts recovery.

Solutions

  1. Replay the snapshot recording from position 0 so the BEGIN marker is included
  2. Re-take the snapshot from a healthy cluster member
  3. Verify the archive replay channel/stream-id and recording start position configuration

Example fix

// before: replay from stored (wrong) offset
replayParams.position(snapshotTailPosition);
// after: replay the whole snapshot recording
replayParams.position(0L);
Defensive patterns

Strategy: validation

Validate before calling

// Replay snapshots from their start position so BEGIN is the first marker
replayParams.position(0L);

Try / catch

try { loader.load(...); } catch (ClusterException e) { abortRecovery(e); }

Prevention

When it happens

Trigger: onFragment receives a SnapshotMarker with mark=END while inSnapshot is false — the first decoded marker was not BEGIN (e.g. replay started after the BEGIN frame or the BEGIN frame was lost/corrupt).

Common situations: Replaying a recording from a wrong starting position (offset past the BEGIN marker), truncated recording that lost the initial frame, or loading only the tail of a snapshot.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/d9a4ad1734b49296. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/service/ServiceSnapshotLoader.java:112

                    throw new ClusterException("unexpected snapshot type: " + typeId);
                }

                switch (snapshotMarkerDecoder.mark())
                {
                    case BEGIN:
                        if (inSnapshot)
                        {
                            throw new ClusterException("already in snapshot");
                        }
                        inSnapshot = true;
                        appVersion = snapshotMarkerDecoder.appVersion();
                        timeUnit = ClusterClock.map(snapshotMarkerDecoder.timeUnit());
                        return Action.CONTINUE;

                    case END:
                        if (!inSnapshot)
                        {
                            throw new ClusterException("missing begin snapshot");
                        }
                        isDone = true;
                        return Action.BREAK;

                    case SECTION:
                    case NULL_VAL:
                        break;
                }
                break;

            case ClientSessionDecoder.TEMPLATE_ID:
                clientSessionDecoder.wrap(
                    buffer,
                    offset + MessageHeaderDecoder.ENCODED_LENGTH,
                    messageHeaderDecoder.blockLength(),
                    messageHeaderDecoder.version());

                final String responseChannel = clientSessionDecoder.responseChannel();

View on GitHub (pinned to 6d60124e15)