stride3d/stride · error · InvalidOperationException

Unexpected null while cloning

Error message

Unexpected null {typeof(T).FullName} while cloning

What it means

Internal clone-serialization error in AssetCloner.PreSerialize (deserialization side): the object resolved from the invariant-object list for the read index is null, i.e. the clone stream referenced an invariant object slot that was never populated during serialization. Points to a mismatch between serialize and deserialize passes of the cloner.

Solutions

  1. Verify the object graph doesn't change between cloning passes (no concurrent mutation)
  2. Ensure a single AssetCloner configuration handles both sides of the clone
  3. Report as an engine bug if it reproduces deterministically
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at sources/assets/Stride.Core.Assets/AssetCloner.cs:358 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/AssetCloner.cs:358

        {
            var invariantObjectList = stream.Context.Get(InvariantObjectListProperty)!;
            if (mode == ArchiveMode.Serialize)
            {
                stream.Write(invariantObjectList.Count);
                invariantObjectList.Add(obj);
            }
            else
            {
                var index = stream.Read<int>();

                if (index >= invariantObjectList.Count)
                {
                    throw new InvalidOperationException($"The type [{typeof(T).FullName}] cannot be only be used for clone serialization");
                }

                if (invariantObjectList[index] is not T invariant)
                {
                    throw new InvalidOperationException($"Unexpected null {typeof(T).FullName} while cloning");
                }

                // Create a new object to avoid exception in case its identity is important
                obj = (T)Activator.CreateInstance(typeof(T), invariant.TypeName, invariant.AssemblyName, invariant.Error, invariant.ParsingEvents)!;
            }
        }

        public override void Serialize(ref T obj, ArchiveMode mode, SerializationStream stream)
        {
            // Process with parent serializer first
            object parentObj = obj;
            parentSerializer?.Serialize(ref parentObj, mode, stream);
            obj = (T)parentObj;
        }
    }
}

View on GitHub (pinned to 96fad776d2)