{"record":{"id":"5a261a2072f28e82","repo":"EllanJiang/GameFramework","slug":"deserialize-callback-0-is-not-exist","errorCode":null,"errorMessage":"Deserialize callback '{0}' is not exist.","messagePattern":"Deserialize callback '(.+?)' is not exist\\.","errorType":"exception","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Base/GameFrameworkSerializer.cs","lineNumber":167,"sourceCode":"        /// </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>\n        /// <returns>是否从指定流获取指定键的值成功。</returns>\n        public bool TryGetValue(Stream stream, string key, out object value)\n        {\n            value = null;\n            byte[] header = GetHeader();\n            byte header0 = (byte)stream.ReadByte();\n            byte header1 = (byte)stream.ReadByte();","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Base/GameFrameworkSerializer.cs#L149-L185","documentation":"GameFrameworkSerializer.Deserialize reads a version byte from the stream and looks up a registered deserialization callback for that version in m_DeserializeCallbacks. When no callback was registered for the version byte found in the stream, it throws this GameFrameworkException instead of silently producing corrupt data. This protects you from deserializing data written by an incompatible serializer version.","triggerScenarios":"Calling Deserialize(stream) when the stream's leading version byte does not match any version passed to the corresponding Register/Serialize path — e.g. data serialized by a newer or older version of the type, or a callback for that version never registered, or the stream position is wrong so the byte read is not actually the version byte.","commonSituations":"Persisted save/data files created before the type's serialized layout changed and no legacy deserialize callback was registered; sharing binary data between builds where one side registered extra version callbacks; calling Deserialize on a stream whose read pointer was not rewound to position 0 so a data byte is misread as the version.","solutions":["Register a deserialize callback for the missing version via the serializer's Register(DeserializeCallback) / versioned registration API before calling Deserialize.","Check the version byte reported in the message ('{0}' is the version number) and confirm which side wrote it; align the serializer versions on both writer and reader.","Verify stream.Position is 0 (or the correct header offset) before calling Deserialize so the version byte is read correctly.","Re-export/re-serialize the data with the current serializer version if legacy callbacks cannot be provided."],"exampleFix":"// before\nbyte[] data = File.ReadAllBytes(path);\nvar obj = serializer.Deserialize(stream); // throws if version has no callback\n\n// after\nserializer.Register(1, DeserializeV1); // register callback for legacy version\nstream.Position = 0;\nvar obj = serializer.Deserialize(stream);","handlingStrategy":"try-catch","validationCode":"// before deserializing\nif (stream.Position != 0) stream.Position = 0;\nint version = stream.PeekByte ?? stream.ReadByte(); // or read into a buffered copy\nbool known = serializer.IsVersionRegistered(version); // if such a check API exists\n// otherwise: keep a HashSet<byte> of versions you registered and check the first byte of the buffer\n","typeGuard":"bool CanDeserialize(byte[] buffer, ISet<byte> registeredVersions) => buffer != null && buffer.Length > 0 && registeredVersions.Contains(buffer[0]);","tryCatchPattern":"try\n{\n    obj = serializer.Deserialize(stream);\n}\ncatch (GameFrameworkException ex) when (ex.Message.Contains(\"is not exist\"))\n{\n    // log stream origin + version, fall back to migration or re-export path\n}","preventionTips":["Always register deserialize callbacks for every historical version of a type before shipping schema changes.","Reset stream.Position to 0 before Deserialize.","Keep serialized data files tagged with the tool/build that produced them."],"tags":["serialization","versioning","deserialization","binary-data"],"backgroundTag":"protobuf-unmarshal-failed","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"}