{"record":{"id":"ea788c39521d7c0e","repo":"stride3d/stride","slug":"legacy-pre-4-2-servicewire-complex-type-serialize-is-not","errorCode":null,"errorMessage":"Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.","messagePattern":"Legacy \\(pre-4\\.2\\) ServiceWire complex-type serialize is not supported\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/launcher/Stride.Cli/Legacy/LegacyServiceWire.cs","lineNumber":34,"sourceCode":"// 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++)\n        {\n            var method = (ClassRecord)methodRecords[i]!;\n            methods[i] = new MethodSyncInfo\n            {\n                MethodIdent = method.GetInt32(Member(method, \"MethodIdent\")),\n                MethodName = method.GetString(Member(method, \"MethodName\")),\n                MethodReturnType = method.GetString(Member(method, \"MethodReturnType\")),","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/launcher/Stride.Cli/Legacy/LegacyServiceWire.cs#L16-L52","documentation":"LegacyBinaryFormatterSerializer implements ServiceWire's ISerializer solely to let the Stride CLI read the BinaryFormatter-encoded handshake payload (ServiceSyncInfo) of Stride 4.1's ServiceWire 5.3.4. BinaryFormatter was removed from modern .NET, so outbound (serialize) calls are deliberately unsupported; only deserializing the single ServiceSyncInfo payload is implemented. This NotSupportedException fires whenever the wire protocol attempts to serialize a complex (non-primitive) object through this legacy serializer.","triggerScenarios":"Calling LegacyBinaryFormatterSerializer.Serialize<T>(obj) or Serialize(obj, typeConfigName) — i.e. the ServiceWire NpClient configured with this legacy serializer attempts to send a complex type across the named-pipe channel instead of a primitive type-code.","commonSituations":"Using the legacy (pre-4.2) serializer combination with a remote method whose parameters are complex types, or invoking any proxy method other than the string/byte[]-based GenerateShaderKeys path the shim was designed for; also发生的 if a custom tool calls the serializer directly.","solutions":["Restrict legacy-serializer use to the supported path: only methods whose arguments are ServiceWire primitive types (strings, byte[]) and whose result is byte[], as the GenerateShaderKeys call in LegacyShaderCodeGenerator does.","If you must send complex types, upgrade the target Stride project to 4.2+ so the modern JSON-based ServiceWire serializer (the default NpClient) can be used instead of the legacy shim.","Serialize the payload yourself into primitives (e.g. JSON string or byte[]) before crossing the ServiceWire boundary.","If this error appears during the handshake only, verify the payload direction: the shim only supports deserializing ServiceSyncInfo, never serializing it."],"exampleFix":"// before (legacy serializer, complex argument)\nproxy.MyMethod(myComplexDto); // throws NotSupportedException\n\n// after (flatten to primitives)\nvar json = JsonSerializer.Serialize(myComplexDto);\nproxy.MyMethod(json); // travels as a string type-code, no serializer needed","handlingStrategy":"validation","validationCode":"// Before invoking a legacy-pipe remote method, assert all parameters are ServiceWire primitives\nstatic void EnsureLegacySafe(object?[] args) {\n    foreach (var a in args)\n        if (a is not (string or byte[] or int or bool or long or double or null))\n            throw new InvalidOperationException(\n                $\"Argument {a?.GetType().Name} requires complex-type serialization, unsupported on the legacy (pre-4.2) ServiceWire shim.\");\n}","typeGuard":"static bool IsLegacySerializable(object? value) =>\n    value is null or string or byte[] or int or bool or long or double or float;","tryCatchPattern":"try {\n    result = proxy.GenerateShaderKeys(name, content);\n}\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"Legacy (pre-4.2) ServiceWire complex-type serialize\")) {\n    // fall back to a modern (4.2+) target or flatten the argument to primitives\n}","preventionTips":["Only use the legacy serializer for the GenerateShaderKeys (string, byte[]) path it was built for.","Prefer targeting Stride 4.2+ so the default JSON serializer handles complex types.","Flatten complex payloads to JSON strings or byte[] before crossing the ServiceWire boundary."],"tags":["servicewire","binaryformatter","serialization","legacy-compatibility","not-supported"],"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"}