aeron-io/aeron · critical · ClusterException
unexpected snapshot type
Error message
unexpected snapshot type: ${typeId} What it means
ServiceSnapshotLoader.onFragment decodes a snapshot replay stream and expects every SnapshotMarker to carry the canonical SNAPSHOT_TYPE_ID. When a marker frame decodes with a different type ID the stream is not an Aeron cluster snapshot the loader understands, so it aborts with a ClusterException rather than misinterpreting the data. This guards against replaying corrupted, truncated, or foreign recordings into cluster services.
Solutions
- Recover the cluster using a snapshot taken by a matching Aeron version (check typeId/appVersion of the snapshot)
- Regenerate the snapshot from a healthy cluster member via a fresh take-snapshot
- Verify the recording ID / archive replay configuration so the correct snapshot recording is loaded
- Inspect the recording with aeron archive tooling to confirm the marker frames' type IDs
Example fix
// before: replaying an old/mismatched recording into recovery
context.clusteredServiceContainer().snapshotStreamChannel("aeron:udp?endpoint=old-snap")...
// after: use the current cluster's recorded snapshot and matching Aeron version
ClusterTool.takeSnapshot(archive, aeron, consensusModuleProxy, countdownLatch); Defensive patterns
Strategy: validation
Validate before calling
// Before replaying, confirm the recording is a current-version cluster snapshot
// e.g. inspect marker frames with Aeron archive tooling and compare typeId/appVersion
if (markerTypeId != SNAPSHOT_TYPE_ID) { throw new IllegalArgumentException("not a snapshot recording: " + markerTypeId); } Try / catch
try { loader.load(...); } catch (ClusterException e) { abortRecovery(e); } Prevention
- Keep all cluster members on the same Aeron version
- Only replay recordings explicitly produced by take-snapshot
- Verify recording IDs in the cluster recovery plan before replay
When it happens
Trigger: Replaying a snapshot recording whose SnapshotMarker decoder yields a typeId != SNAPSHOT_TYPE_ID, e.g. a recording from a different Aeron version or a non-snapshot recording fed to snapshot recovery.
Common situations: Pointing cluster recovery at the wrong recording (an old or foreign log/snapshot), snapshot files produced by a different Aeron protocol version, or corrupted recording files whose headers decode as a different type.
Related errors
- already in snapshot
- missing begin snapshot
- publication is not connected
- publication is closed
- publication at max position: term-length=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/7e60e3d277bda2de.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/service/ServiceSnapshotLoader.java:94
final int schemaId = messageHeaderDecoder.schemaId();
if (MessageHeaderDecoder.SCHEMA_ID != schemaId)
{
throw new ClusterException("expected schemaId=" + MessageHeaderDecoder.SCHEMA_ID + ", actual=" + schemaId);
}
switch (messageHeaderDecoder.templateId())
{
case SnapshotMarkerDecoder.TEMPLATE_ID:
snapshotMarkerDecoder.wrap(
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
final long typeId = snapshotMarkerDecoder.typeId();
if (SNAPSHOT_TYPE_ID != typeId)
{
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");View on GitHub (pinned to 6d60124e15)