stride3d/stride · error · InvalidOperationException

SetAssetObject has already been called with a different…

Error message

SetAssetObject has already been called with a different object

What it means

ContentManager.SetAssetObject registers a deserialized object instance onto an object reference. If the reference already holds a different object instance, the internal object/reference bookkeeping is inconsistent, so the library throws InvalidOperationException to surface the corruption early rather than silently swapping assets.

Solutions

  1. Do not reuse the same ObjectReference instance for two different asset objects; create a fresh reference per deserialization
  2. Ensure the object passed to SetAssetObject is the exact instance already assigned to reference.Object (reference equality)
  3. If intentionally replacing, null out reference.Object before calling SetAssetObject
  4. Audit custom serialization code (IDataSerializer implementations) that may share references between asset instances

Example fix

// before
reference.Object = otherInstance;
manager.SetAssetObject(reference, newObj); // throws
// after
var freshReference = new ObjectReference(reference.Url);
manager.SetAssetObject(freshReference, newObj);
Defensive patterns

Strategy: try-catch

Validate before calling

if (reference.Object != null && !ReferenceEquals(reference.Object, obj))
    throw new InvalidOperationException("Reference already bound to a different object");

Type guard

static bool CanSetAssetObject(ObjectReference r, object obj) => r.Object == null || ReferenceEquals(r.Object, obj);

Try / catch

try { manager.SetAssetObject(reference, obj); }
catch (InvalidOperationException) { // reference already bound to a different object
  reference.Object = null; manager.SetAssetObject(reference, obj); }

Prevention

When it happens

Trigger: Calling SetAssetObject with an object that differs from the one already stored in reference.Object; happens internally via RegisterDeserializedObject, DeserializeObject, or SerializeObject when the same ObjectReference is reused across two different asset instances.

Common situations: Reusing a loaded asset's ObjectReference as the target for a second deserialization; sharing asset references across two ContentManager loads; a serialization bug that leaves a stale Object property on a reference being repopulated.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/eadb1bcb3d4b9207. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Serialization/Serialization/Contents/ContentManager.cs:631

                if (attachedReference?.IsProxy != false)
                    continue;

                serializeOperations.Enqueue(new SerializeOperation(contentReference.Location, contentReference.ObjectValue, false));
            }
        }
    }

    /// <summary>
    /// Sets Reference.Object, and updates loadedAssetByUrl collection.
    /// </summary>
    internal void SetAssetObject(Reference reference, object obj)
    {
        ArgumentNullException.ThrowIfNull(obj);

        if (reference.Object != null)
        {
            if (reference.Object != obj)
                throw new InvalidOperationException("SetAssetObject has already been called with a different object");

            return;
        }

        var url = reference.Url;
        reference.Object = obj;

        lock (LoadedAssetUrls)
        {
            if (LoadedAssetUrls.TryGetValue(url, out var previousReference))
            {
                reference.Next = previousReference.Next;
                reference.Prev = previousReference;

                if (previousReference.Next != null)
                    previousReference.Next.Prev = reference;
                previousReference.Next = reference;
            }

View on GitHub (pinned to 96fad776d2)