stride3d/stride · error · InvalidOperationException

The path [ ] contains access to a member of a null object.

Error message

The path [{ToString()}] contains access to a member of a null object.

What it means

YamlAssetPath.ToMemberPath resolves the stored path against a root object, walking members/indices/item-ids. If the walk reaches a point where currentObject is null but the path continues, it throws InvalidOperationException('The path [...] contains access to a member of a null object.') — the path references data that does not exist in the object graph.

Solutions

  1. Null-check intermediate members before applying the path, and skip/rebase the path if null
  2. Validate the path against the current object graph (TryResolve) before conversion
  3. Fix the earlier processing step that nulled the intermediate object
  4. Regenerate the paths from the current object instead of reusing stale recorded paths

Example fix

// before
var memberPath = path.ToMemberPath(asset);
// after
object probe = asset;
bool ok = true;
foreach (var el in path.Elements)
{
    if (probe is null) { ok = false; break; }
    probe = ResolveStep(probe, el); // your resolution helper
}
var memberPath = ok ? path.ToMemberPath(asset) : null;
Defensive patterns

Strategy: validation

Validate before calling

object probe = root;
foreach (var el in path.Elements)
{
    if (probe is null) return false; // path would hit null
    probe = Resolve(probe, el);
}
var memberPath = path.ToMemberPath(root);

Type guard

bool ResolvesWithoutNull(object root, YamlAssetPath path) =>
    path.Elements.All(e => (Peek(ref root, e)) is not null); // Peek advances on non-null

Try / catch

try { var mp = path.ToMemberPath(root); }
catch (InvalidOperationException ex) { logger.Warn(ex, $"Path hits null object: {path}"); return null; }

Prevention

When it happens

Trigger: Calling ToMemberPath(root) with a path that descends into a member/index whose value is null in the actual object, e.g. a path recorded for an object whose parent reference was nulled by an earlier fixup.

Common situations: Applying recorded asset-upgrade/metadata paths to objects whose structure changed (member now null); partially-failed deserialization leaving null intermediate objects; scripts applying paths from one asset version to another.

Related errors


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Yaml/YamlAssetPath.cs:228

    {
        var clone = new YamlAssetPath(elements);
        return clone;
    }

    /// <summary>
    /// Convert this <see cref="YamlAssetPath"/> into a <see cref="MemberPath"/>.
    /// </summary>
    /// <param name="root">The actual instance that is root of this path.</param>
    /// <returns>An instance of <see cref="MemberPath"/> corresponding to the same target than this <see cref="YamlAssetPath"/>.</returns>
    [Pure]
    public MemberPath ToMemberPath(object root)
    {
        var currentObject = root;
        var memberPath = new MemberPath();
        foreach (var item in Elements)
        {
            if (currentObject is null)
                throw new InvalidOperationException($"The path [{ToString()}] contains access to a member of a null object.");

            switch (item.Type)
            {
                case ElementType.Member:
                    {
                        var typeDescriptor = TypeDescriptorFactory.Default.Find(currentObject.GetType());
                        var name = item.AsMember();
                        var memberDescriptor = typeDescriptor.Members.FirstOrDefault(x => x.Name == name)
                            ?? throw new InvalidOperationException($"The path [{ToString()}] contains access to non-existing member [{name}].");
                        memberPath.Push(memberDescriptor);
                        currentObject = memberDescriptor.Get(currentObject);
                        break;
                    }
                case ElementType.Index:
                    {
                        var typeDescriptor = TypeDescriptorFactory.Default.Find(currentObject.GetType());
                        if (typeDescriptor is ArrayDescriptor arrayDescriptor)
                        {

View on GitHub (pinned to 96fad776d2)