{"record":{"id":"a7f391f9c5bb6f8b","repo":"EllanJiang/GameFramework","slug":"header-is-invalid-need-0-1-2-current-3-4-5","errorCode":null,"errorMessage":"Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.","messagePattern":"Header is invalid, need '(.+?)(.+?)(.+?)', current '(.+?)(.+?)(.+?)'\\.","errorType":"exception","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Base/GameFrameworkSerializer.cs","lineNumber":160,"sourceCode":"            }\n\n            return callback(stream, data);\n        }\n\n        /// <summary>\n        /// 从指定流反序列化数据。\n        /// </summary>\n        /// <param name=\"stream\">指定流。</param>\n        /// <returns>反序列化的数据。</returns>\n        public T Deserialize(Stream stream)\n        {\n            byte[] header = GetHeader();\n            byte header0 = (byte)stream.ReadByte();\n            byte header1 = (byte)stream.ReadByte();\n            byte header2 = (byte)stream.ReadByte();\n            if (header0 != header[0] || header1 != header[1] || header2 != header[2])\n            {\n                throw new GameFrameworkException(Utility.Text.Format(\"Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.\", (char)header[0], (char)header[1], (char)header[2], (char)header0, (char)header1, (char)header2));\n            }\n\n            byte version = (byte)stream.ReadByte();\n            DeserializeCallback callback = null;\n            if (!m_DeserializeCallbacks.TryGetValue(version, out callback))\n            {\n                throw new GameFrameworkException(Utility.Text.Format(\"Deserialize callback '{0}' is not exist.\", version));\n            }\n\n            return callback(stream);\n        }\n\n        /// <summary>\n        /// 尝试从指定流获取指定键的值。\n        /// </summary>\n        /// <param name=\"stream\">指定流。</param>\n        /// <param name=\"key\">指定键。</param>\n        /// <param name=\"value\">指定键的值。</param>","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Base/GameFrameworkSerializer.cs#L142-L178","documentation":"Deserialize reads a 3-byte magic header from the stream and compares it to GetHeader() (the serializer's expected signature bytes). It throws when the bytes in the stream differ from the expected header, formatting both expected and actual header characters into the message. This protects against deserializing data that was not produced by this serializer type.","triggerScenarios":"Calling serializer.Deserialize(stream) on a stream whose first three bytes don't match the expected header — e.g. an empty/truncated stream (ReadByte returns -1 cast to byte 255), a file saved by a different serializer type T, or a corrupted/manually edited save file.","commonSituations":"Loading a save file written by another game/framework version with a changed header; reading a config file with the deserializer that was never serialized by it; corrupted downloads; reading from a stream positioned mid-file rather than at position 0.","solutions":["Ensure the stream position is 0 and the data was produced by GameFrameworkSerializer<T>.Serialize for the same T.","Verify the file is a complete, non-empty serialized blob (not truncated or overwritten).","Regenerate the file with the current serializer, or keep a legacy reader that accepts the old header.","Pre-validate the first three bytes against the expected header and show a 'corrupt save' path instead of throwing."],"exampleFix":"// before\nvar data = serializer.Deserialize(File.OpenRead(path)); // may be wrong file\n// after\nusing (var stream = File.OpenRead(path))\n{\n    if (stream.Length >= 3 && serializer.CheckHeader(stream)) // or compare GetHeader()\n    {\n        var data = serializer.Deserialize(stream);\n    }\n    else\n    {\n        data = PlayerData.CreateDefault(); // fallback for corrupt/foreign files\n    }\n}","handlingStrategy":"try-catch","validationCode":"using (var fs = File.OpenRead(path))\n{\n    if (fs.Length < 3) { return CreateDefault(); }\n    var expected = GetHeaderBytes();\n    var actual = new byte[3];\n    if (fs.Read(actual, 0, 3) != 3 || !actual.SequenceEqual(expected)) { return CreateDefault(); }\n    fs.Position = 0;\n    return serializer.Deserialize(fs);\n}","typeGuard":"static bool LooksLikeSerializerBlob(FileStream fs, byte[] expectedHeader) => fs != null && fs.Length >= 3;","tryCatchPattern":"try { data = serializer.Deserialize(stream); } catch (GameFrameworkException ex) { log.Warning(\"Save file header mismatch, using defaults: \" + ex.Message); data = PlayerData.CreateDefault(); }","preventionTips":["Always deserialize from position 0 on streams you wrote with Serialize","Verify file size and header before deserializing saves","Version the save format and keep legacy readers","Never feed non-serializer files (configs, JSON) to Deserialize"],"tags":["csharp","header-mismatch","serialization","corrupt-data"],"backgroundTag":"checksum-mismatch","analyzedSha":"d0c010b05167c58e92350449d04864a91ca13fd2","analyzedAt":"2026-09-15T13:37:15.352Z","contentChangedAt":"2026-09-15T13:37:15.352Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}