{"record":{"id":"8c75c504ad91289e","repo":"stride3d/stride","slug":"legacy-pre-4-2-servicewire-deserialize-of-typeof-t-is-not","errorCode":null,"errorMessage":"Legacy (pre-4.2) ServiceWire deserialize of {typeof(T)} is not supported.","messagePattern":"Legacy \\(pre-4\\.2\\) ServiceWire deserialize of (.+?) is not supported\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/launcher/Stride.Cli/Legacy/LegacyServiceWire.cs","lineNumber":27,"sourceCode":"namespace Stride.Cli.Legacy;\n\n// Stride 4.1 shipped ServiceWire 5.3.4, whose default serializer is BinaryFormatter, and its Commands server\n// serializes the ServiceWire handshake payload (ServiceSyncInfo — the remote method table) that way. Later\n// ServiceWire (4.2+) switched to a JSON serializer, which the stock client already speaks.\n//\n// BinaryFormatter is gone from modern .NET, so we can't round-trip that payload with the stock serializer.\n// It's the only serializer call on the client's GenerateShaderKeys path, though: the method's string arguments\n// and byte[] result travel as ServiceWire primitive type-codes, never through the serializer. So we only need\n// to read that one payload, which we do with the safe NRBF reader and rebuild ServiceSyncInfo by hand.\ninternal sealed class LegacyBinaryFormatterSerializer : ISerializer\n{\n    public T Deserialize<T>(byte[] bytes)\n    {\n        if (bytes is null || bytes.Length == 0)\n            return default!;\n        if (typeof(T) == typeof(ServiceSyncInfo))\n            return (T)(object)ReadServiceSyncInfo(bytes);\n        throw new NotSupportedException($\"Legacy (pre-4.2) ServiceWire deserialize of {typeof(T)} is not supported.\");\n    }\n\n    public object Deserialize(byte[] bytes, string typeConfigName)\n        => throw new NotSupportedException(\"Legacy (pre-4.2) ServiceWire complex-type deserialize is not supported.\");\n\n    public byte[] Serialize<T>(T obj)\n        => throw new NotSupportedException(\"Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.\");\n\n    public byte[] Serialize(object obj, string typeConfigName)\n        => throw new NotSupportedException(\"Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.\");\n\n    private static ServiceSyncInfo ReadServiceSyncInfo(byte[] bytes)\n    {\n        var root = (ClassRecord)NrbfDecoder.Decode(new MemoryStream(bytes));\n\n        var methodRecords = ((SZArrayRecord<SerializationRecord>)root.GetArrayRecord(Member(root, \"MethodInfos\"))).GetArray();\n        var methods = new MethodSyncInfo[methodRecords.Length];\n        for (var i = 0; i < methodRecords.Length; i++)","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/launcher/Stride.Cli/Legacy/LegacyServiceWire.cs#L9-L45","documentation":"LegacyServiceWire.Deserialize<T> only supports deserializing byte payloads into ServiceSyncInfo (the only type legacy pre-4.2 wire traffic needs for sync info); an empty/null payload returns default. Any other T reaches the NotSupportedException. It exists to plug a legacy serializer into newer infrastructure without reimplementing full legacy serialization.","triggerScenarios":"Calling Deserialize<T> with T other than ServiceSyncInfo, e.g. Deserialize<MyMessage>(bytes), against the legacy pre-4.2 ServiceWire adapter.","commonSituations":"Migrating code that talked to pre-4.2 Stride game-studio/service processes and trying to exchange complex typed messages over the legacy channel; porting old IPC tests.","solutions":["Restrict legacy-wire usage to ServiceSyncInfo deserialization only.","Use the current (post-4.2) ServiceWire serializer for complex types instead of the Legacy adapter.","Add an explicit overload or wrapper that throws a clearer domain error if you expect complex types in legacy scenarios."],"exampleFix":"// before\nvar msg = legacyWire.Deserialize<MyServiceMessage>(bytes); // throws\n// after\nvar info = legacyWire.Deserialize<ServiceSyncInfo>(bytes);","handlingStrategy":"type-guard","validationCode":"if (typeof(T) != typeof(ServiceSyncInfo))\n    throw new NotSupportedException(\"Legacy wire supports only ServiceSyncInfo deserialization.\");","typeGuard":"bool IsLegacySupported<T>() => typeof(T) == typeof(ServiceSyncInfo);","tryCatchPattern":"try { return legacyWire.Deserialize<T>(bytes); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"not supported\")) {\n    // fall back to the modern ServiceWire serializer for complex types\n    return modernWire.Deserialize<T>(bytes);\n}","preventionTips":["Only call the legacy adapter for ServiceSyncInfo payloads.","Add a compile-time wrapper constraining T to ServiceSyncInfo.","Document the legacy adapter's scope in team onboarding for the 4.1->4.2 migration."],"tags":["serialization","legacy","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}