stride3d/stride · error · NotSupportedException
Legacy (pre-4.2) ServiceWire complex-type serialize is not s
Error message
Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.
What it means
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.
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.
Example fix
// before (legacy serializer, complex argument) proxy.MyMethod(myComplexDto); // throws NotSupportedException // after (flatten to primitives) var json = JsonSerializer.Serialize(myComplexDto); proxy.MyMethod(json); // travels as a string type-code, no serializer needed
Defensive patterns
Strategy: validation
Validate before calling
// Before invoking a legacy-pipe remote method, assert all parameters are ServiceWire primitives
static void EnsureLegacySafe(object?[] args) {
foreach (var a in args)
if (a is not (string or byte[] or int or bool or long or double or null))
throw new InvalidOperationException(
$"Argument {a?.GetType().Name} requires complex-type serialization, unsupported on the legacy (pre-4.2) ServiceWire shim.");
} Type guard
static bool IsLegacySerializable(object? value) =>
value is null or string or byte[] or int or bool or long or double or float; Try / catch
try {
result = proxy.GenerateShaderKeys(name, content);
}
catch (NotSupportedException ex) when (ex.Message.Contains("Legacy (pre-4.2) ServiceWire complex-type serialize")) {
// fall back to a modern (4.2+) target or flatten the argument to primitives
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Two bundles with name {0} found
- {mismatches} content reference(s) were not rooted (see error
- Cyclic dependency found, involving {0}
- Unable to find a serializer for [{0}]
- Unable to find a serializer for the specified asset. No asse
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ea788c39521d7c0e.
Report an issue: GitHub.
Appendix: source
Thrown at sources/launcher/Stride.Cli/Legacy/LegacyServiceWire.cs:34
// It's the only serializer call on the client's GenerateShaderKeys path, though: the method's string arguments
// and byte[] result travel as ServiceWire primitive type-codes, never through the serializer. So we only need
// to read that one payload, which we do with the safe NRBF reader and rebuild ServiceSyncInfo by hand.
internal sealed class LegacyBinaryFormatterSerializer : ISerializer
{
public T Deserialize<T>(byte[] bytes)
{
if (bytes is null || bytes.Length == 0)
return default!;
if (typeof(T) == typeof(ServiceSyncInfo))
return (T)(object)ReadServiceSyncInfo(bytes);
throw new NotSupportedException($"Legacy (pre-4.2) ServiceWire deserialize of {typeof(T)} is not supported.");
}
public object Deserialize(byte[] bytes, string typeConfigName)
=> throw new NotSupportedException("Legacy (pre-4.2) ServiceWire complex-type deserialize is not supported.");
public byte[] Serialize<T>(T obj)
=> throw new NotSupportedException("Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.");
public byte[] Serialize(object obj, string typeConfigName)
=> throw new NotSupportedException("Legacy (pre-4.2) ServiceWire complex-type serialize is not supported.");
private static ServiceSyncInfo ReadServiceSyncInfo(byte[] bytes)
{
var root = (ClassRecord)NrbfDecoder.Decode(new MemoryStream(bytes));
var methodRecords = ((SZArrayRecord<SerializationRecord>)root.GetArrayRecord(Member(root, "MethodInfos"))).GetArray();
var methods = new MethodSyncInfo[methodRecords.Length];
for (var i = 0; i < methodRecords.Length; i++)
{
var method = (ClassRecord)methodRecords[i]!;
methods[i] = new MethodSyncInfo
{
MethodIdent = method.GetInt32(Member(method, "MethodIdent")),
MethodName = method.GetString(Member(method, "MethodName")),
MethodReturnType = method.GetString(Member(method, "MethodReturnType")),View on GitHub (pinned to 96fad776d2)