microsoft/garnet · critical · Exception
invalid metadata length: {hlri.cookie.Length} < 4
Error message
invalid metadata length: {hlri.cookie.Length} < 4 What it means
Thrown during legacy single-log checkpoint cookie deserialization when the cookie byte buffer is shorter than 4 bytes, too small to read the leading int cookieSize. This indicates a truncated, corrupt, or incompatible checkpoint metadata blob. The code runs in an unsafe fixed block reading primitive sizes directly from the buffer.
Source
Thrown at libs/cluster/Server/Replication/GarnetClusterCheckpointManager.cs:121
/// Retrieve RecoveredSafeAofAddress and RecoveredReplicationId for checkpoint
/// </summary>
/// <param name="logToken"></param>
/// <param name="recoveredSafeAofAddress"></param>
/// <param name="recoveredReplicationId"></param>
/// <exception cref="Exception"></exception>
public unsafe void GetCheckpointCookieMetadata(Guid logToken, ref AofAddress recoveredSafeAofAddress, out string recoveredReplicationId)
{
var metadata = GetLogCheckpointMetadata(logToken);
var hlri = ConvertMetadata(metadata);
recoveredReplicationId = null;
if (RecoveredSafeAofAddress.Length == 1)
{
// Legacy single log deserialization for backward compatibility
var bytesRead = sizeof(int);
fixed (byte* ptr = hlri.cookie)
{
if (hlri.cookie.Length < 4) throw new Exception($"invalid metadata length: {hlri.cookie.Length} < 4");
var cookieSize = *(int*)ptr;
bytesRead += cookieSize;
if (hlri.cookie.Length < 12) throw new Exception($"invalid metadata length: {hlri.cookie.Length} < 12");
recoveredSafeAofAddress[0] = *(long*)(ptr + 4);
if (hlri.cookie.Length < 52) throw new Exception($"invalid metadata length: {hlri.cookie.Length} < 52");
recoveredReplicationId = Encoding.ASCII.GetString(ptr + 12, 40);
}
}
else
{
// Multi-log cookie
using var ms = new MemoryStream(hlri.cookie);
using var reader = new BinaryReader(ms, Encoding.ASCII);
recoveredReplicationId = reader.ReadInt32() > 0 ? reader.ReadString() : null;
recoveredSafeAofAddress = AofAddress.Deserialize(reader);
reader.Dispose();View on GitHub (pinned to 951b0fc683)
Solutions
- Restore from a known-good full checkpoint instead of the corrupt one.
- Verify checkpoint file integrity and version compatibility before recovery.
- If upgrading across versions that changed the cookie format, take a fresh full checkpoint after upgrade.
Defensive patterns
Strategy: validation
Validate before calling
// Validate cookie length before unsafe reads
if (hlri.cookie == null || hlri.cookie.Length < 4)
throw new InvalidDataException($"Checkpoint cookie too short ({hlri?.cookie?.Length ?? -1} bytes); checkpoint may be corrupt or from an incompatible version"); Try / catch
try { manager.GetCheckpointCookieMetadata(logToken, ref addr, out var id); }
catch (Exception ex) when (ex.Message.Contains("invalid metadata length"))
{
logger?.LogError(ex, "Corrupt/incompatible checkpoint cookie for log {logToken}; recovering from a full checkpoint instead", logToken);
// fall back to a known-good full checkpoint
} Prevention
- Keep known-good full checkpoints for disaster recovery.
- Take a fresh full checkpoint after any version upgrade that changes cookie format.
- Validate checkpoint file integrity before attempting recovery.
When it happens
Trigger: GetCheckpointCookieMetadata on a checkpoint whose embedded cookie is < 4 bytes — a malformed or partially-written checkpoint recovered from an older/incompatible version.
Common situations: Recovering a checkpoint from an incompatible Garnet version that wrote a differently-shaped cookie; a checkpoint file truncated by a crash mid-write; manual corruption of checkpoint metadata files on disk.
Related errors
- invalid metadata length: {hlri.cookie.Length} < 12
- Option {fileType} not supported
- Checkpoint history unavailable, need full checkpoint for {en
- Failed to validate main store metadata at insertion
- RetrieveCheckpointFile: unexpected state{retStateType}
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/5699f8e668d0c9e2.
Report an issue: GitHub.