stride3d/stride · error · InvalidOperationException
Error when serializing reference.
Error message
Error when serializing reference.
What it means
In ArchiveMode.Serialize, ReferenceSerializer writes the object's attached reference (Id + Url). If the object has no attached reference or its Url is null, there is no location to write, so the library throws instead of emitting an unresolvable reference.
Solutions
- Ensure the object was created/loaded through the ContentManager so it has an attached reference with a Url
- Attach reference metadata manually via AttachedReferenceManager before serializing
- Skip/guard serialization paths that only need hashes by giving the object a valid Url
Example fix
// before
var tex = new Texture();
contentManager.Save("out", wrapper); // throws: no attached reference
// after
var tex = contentManager.Load<Texture>("my-texture"); // has attached reference
contentManager.Save("out", wrapper); Defensive patterns
Strategy: validation
Validate before calling
var ar = AttachedReferenceManager.GetAttachedReference(obj);
if (ar?.Url == null) throw new InvalidOperationException($"{obj.GetType().Name} has no attached content reference; load it via ContentManager"); Type guard
static bool IsSerializableReference(object o) => AttachedReferenceManager.GetAttachedReference(o)?.Url != null;
Try / catch
try { SerializeRef(stream, obj); }
catch (InvalidOperationException ex) when (ex.Message == "Error when serializing reference.") { // object lacks attached reference
} Prevention
- Only serialize objects obtained from ContentManager
- Attach reference metadata manually for in-memory objects that must be persisted
- Unit-test reference serialization for custom object lifecycles
When it happens
Trigger: Serializing an object that is an IReferencable without attached reference metadata (not created/tracked by the content system), e.g. during build engine command hash computation when the object was constructed in memory rather than loaded.
Common situations: Manually instantiating an asset class with 'new' and saving it; passing a runtime-created object into a serialization path that expects content-managed objects; objects whose AttachedReference was stripped.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Unable to find a serializer for
- SetAssetObject has already been called with a different…
- Could not find a valid content serializer for
- Unable to find the base
- Unable to find the graph corresponding to the base part
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/c3f78e9d7db6fc1d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Serialization/Serialization/Contents/ReferenceSerializer.cs:88
}
}
}
}
else if (referenceSerialization == ContentSerializerContext.AttachedReferenceSerialization.AsNull)
{
if (mode == ArchiveMode.Deserialize)
{
obj = default;
}
}
else if (referenceSerialization == ContentSerializerContext.AttachedReferenceSerialization.AsSerializableVersion)
{
if (mode == ArchiveMode.Serialize)
{
// This case will happen when serializing build engine command hashes: we still want Location to still be written
var attachedReference = AttachedReferenceManager.GetAttachedReference(obj);
if (attachedReference?.Url == null)
throw new InvalidOperationException("Error when serializing reference.");
// TODO: Do not use string
stream.Write(obj.GetType().AssemblyQualifiedName);
stream.Write(attachedReference.Id);
stream.Write(attachedReference.Url);
}
else
{
var type = AssemblyRegistry.GetType(stream.ReadString());
var id = stream.Read<AssetId>();
var url = stream.ReadString();
obj = (T)AttachedReferenceManager.CreateProxyObject(type, id, url);
}
}
else if (referenceSerialization == ContentSerializerContext.AttachedReferenceSerialization.Clone)
{
var cloneReferences = stream.Context.Get(ReferenceSerializer.CloneReferences);View on GitHub (pinned to 96fad776d2)