stride3d/stride · error · InvalidOperationException
Non-scalar key not yet supported!
Error message
Non-scalar key not yet supported!
What it means
KeyWithIdSerializer.ConvertFrom deserializes dictionary keys of KeyWithId<K,V> but only supports scalar (string-like) keys. When the key serializer for the dictionary's key type is not a ScalarSerializerBase, it throws InvalidOperationException('Non-scalar key not yet supported!'). It is a documented limitation (TODO in source).
Solutions
- Change the dictionary key type to a scalar (string, int, Guid, PropertyKey, etc.)
- Keep the complex key as a dictionary value and use a scalar identifier as the key
- Implement a ScalarSerializerBase for the key type so it round-trips as a scalar string
- Replace KeyWithId-keyed collections with lists or another supported collection shape
Example fix
// before
public DictionaryWithItemIds<MyComplexKey, int> Items { get; set; }
// after
public DictionaryWithItemIds<string, int> Items { get; set; } // use MyComplexKey.Id Defensive patterns
Strategy: validation
Validate before calling
var keyDesc = context.FindTypeDescriptor(typeof(TKey));
var ser = context.Serializer.GetSerializer(context, keyDesc);
if (ser is not ScalarSerializerBase) throw new InvalidOperationException("Dictionary key must be scalar for KeyWithId serialization"); Type guard
bool IsScalarKey<TKey>(SerializerContext ctx) =>
ctx.Serializer.GetSerializer(ctx, ctx.FindTypeDescriptor(typeof(TKey))) is ScalarSerializerBase; Try / catch
try { var value = serializer.ConvertFrom(ref objectContext); }
catch (InvalidOperationException ex) { logger.Error(ex, "Non-scalar dictionary key in asset"); throw; } Prevention
- Use scalar types (string, int, Guid) as dictionary keys in asset types
- Provide a ScalarSerializerBase for custom key types
- Avoid changing key types to complex objects in asset schemas
When it happens
Trigger: Deserializing an asset YAML containing a DictionaryWithItemIds (or KeyWithId keys) whose key type is a complex/non-scalar object (e.g. a struct or class key) rather than a scalar like string or int.
Common situations: Asset types using dictionaries keyed by composite objects; schema evolution where a scalar key type was changed to a complex key type; custom asset types with non-primitive dictionary keys.
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
- Cannot add item with key
- Multiple identifiable objects with the same id
- Unable to decode asset part reference
- Unable to deserialize reference
- Unable to find class from tag
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ebe4bf151e804510.
Report an issue: GitHub.
Appendix: source
Thrown at sources/assets/Stride.Core.Assets/Yaml/KeyWithIdSerializer.cs:39
/// <inheritdoc/>
public override object? ConvertFrom(ref ObjectContext objectContext, Scalar fromScalar)
{
var idIndex = fromScalar.Value.IndexOf('~');
var id = ItemId.Empty;
var keyString = fromScalar.Value;
if (idIndex >= 0)
{
var idString = fromScalar.Value[..idIndex];
keyString = fromScalar.Value[(idIndex + 1)..];
id = ItemId.Parse(idString);
}
var keyType = objectContext.Descriptor.Type.GetGenericArguments()[0];
var keyDescriptor = objectContext.SerializerContext.FindTypeDescriptor(keyType);
var keySerializer = objectContext.SerializerContext.Serializer.GetSerializer(objectContext.SerializerContext, keyDescriptor);
// TODO: deserialize non-scalar keys!
if (keySerializer is not ScalarSerializerBase scalarKeySerializer)
throw new InvalidOperationException("Non-scalar key not yet supported!");
if (keyString.Length == 0)
return Activator.CreateInstance(typeof(DeletedKeyWithId<>).MakeGenericType(keyType), id);
var context = new ObjectContext(objectContext.SerializerContext, null, keyDescriptor);
var key = scalarKeySerializer.ConvertFrom(ref context, new Scalar(keyString));
var result = Activator.CreateInstance(typeof(KeyWithId<>).MakeGenericType(keyType), id, key);
return result;
}
/// <inheritdoc/>
public override string ConvertTo(ref ObjectContext objectContext)
{
var key = (IKeyWithId)objectContext.Instance;
var keyDescriptor = objectContext.SerializerContext.FindTypeDescriptor(key.KeyType);
var keySerializer = objectContext.SerializerContext.Serializer.GetSerializer(objectContext.SerializerContext, keyDescriptor);
// TODO: serialize non-scalar keys!View on GitHub (pinned to 96fad776d2)