{"record":{"id":"5699f8e668d0c9e2","repo":"microsoft/garnet","slug":"invalid-metadata-length-hlri-cookie-length-4","errorCode":null,"errorMessage":"invalid metadata length: {hlri.cookie.Length} < 4","messagePattern":"invalid metadata length: (.+?) < 4","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"libs/cluster/Server/Replication/GarnetClusterCheckpointManager.cs","lineNumber":121,"sourceCode":"        /// Retrieve RecoveredSafeAofAddress and RecoveredReplicationId for checkpoint\n        /// </summary>\n        /// <param name=\"logToken\"></param>\n        /// <param name=\"recoveredSafeAofAddress\"></param>\n        /// <param name=\"recoveredReplicationId\"></param>\n        /// <exception cref=\"Exception\"></exception>\n        public unsafe void GetCheckpointCookieMetadata(Guid logToken, ref AofAddress recoveredSafeAofAddress, out string recoveredReplicationId)\n        {\n            var metadata = GetLogCheckpointMetadata(logToken);\n            var hlri = ConvertMetadata(metadata);\n\n            recoveredReplicationId = null;\n            if (RecoveredSafeAofAddress.Length == 1)\n            {\n                // Legacy single log deserialization for backward compatibility\n                var bytesRead = sizeof(int);\n                fixed (byte* ptr = hlri.cookie)\n                {\n                    if (hlri.cookie.Length < 4) throw new Exception($\"invalid metadata length: {hlri.cookie.Length} < 4\");\n                    var cookieSize = *(int*)ptr;\n                    bytesRead += cookieSize;\n\n                    if (hlri.cookie.Length < 12) throw new Exception($\"invalid metadata length: {hlri.cookie.Length} < 12\");\n                    recoveredSafeAofAddress[0] = *(long*)(ptr + 4);\n\n                    if (hlri.cookie.Length < 52) throw new Exception($\"invalid metadata length: {hlri.cookie.Length} < 52\");\n                    recoveredReplicationId = Encoding.ASCII.GetString(ptr + 12, 40);\n                }\n            }\n            else\n            {\n                // Multi-log cookie\n                using var ms = new MemoryStream(hlri.cookie);\n                using var reader = new BinaryReader(ms, Encoding.ASCII);\n                recoveredReplicationId = reader.ReadInt32() > 0 ? reader.ReadString() : null;\n                recoveredSafeAofAddress = AofAddress.Deserialize(reader);\n                reader.Dispose();","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/cluster/Server/Replication/GarnetClusterCheckpointManager.cs#L103-L139","documentation":"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.","triggerScenarios":"GetCheckpointCookieMetadata on a checkpoint whose embedded cookie is < 4 bytes — a malformed or partially-written checkpoint recovered from an older/incompatible version.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate cookie length before unsafe reads\nif (hlri.cookie == null || hlri.cookie.Length < 4)\n    throw new InvalidDataException($\"Checkpoint cookie too short ({hlri?.cookie?.Length ?? -1} bytes); checkpoint may be corrupt or from an incompatible version\");","typeGuard":null,"tryCatchPattern":"try { manager.GetCheckpointCookieMetadata(logToken, ref addr, out var id); }\ncatch (Exception ex) when (ex.Message.Contains(\"invalid metadata length\"))\n{\n    logger?.LogError(ex, \"Corrupt/incompatible checkpoint cookie for log {logToken}; recovering from a full checkpoint instead\", logToken);\n    // fall back to a known-good full checkpoint\n}","preventionTips":["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."],"tags":["cluster","replication","checkpoint","serialization","data-integrity","garnet"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}