stride3d/stride · error · InvalidOperationException

The path [ ] contains a null item on a set.

Error message

The path [{ToString()}] contains a null item on a set.

What it means

Thrown by YamlAssetPath.ToMemberPath when a path element references a null item in a set whose element type does not allow nulls. Sets are addressed by the item value itself, so a null (or a null not permitted by the element type) cannot identify any member and the conversion is aborted.

Solutions

  1. Remove the null entry from the path in the asset YAML or regenerate the reference to point at an actual set element
  2. If nulls are legitimate, change the set's element type to a nullable one in the asset class
  3. Fix code that builds the YamlAssetPath so it never pushes a null item for a set
  4. Catch InvalidOperationException in ToMemberPath callers and log the path for diagnosis

Example fix

// before (asset yaml)
setItems: [null]
// after
setItems: [myItemId]
Defensive patterns

Strategy: validation

Validate before calling

if (item.Value is null && !elementType.IsNullable()) throw new ArgumentException("Set items cannot be null for non-nullable element types");

Type guard

bool IsValidSetItem(object v) => v != null;

Try / catch

try { memberPath = yamlPath.ToMemberPath(); } catch (InvalidOperationException ex) { log.Error($"Invalid set reference in '{yamlPath}': {ex.Message}"); }

Prevention

When it happens

Trigger: ToMemberPath processes an element whose parent resolves to a SetDescriptor and item.Value is null while collectionDescriptor.ElementType.IsNullable() is false.

Common situations: A YAML asset path referencing an empty/null entry of a HashSet-based property; schema changes that made a set's element type non-nullable after the asset was authored; hand-edited YAML inserting a null set key.

Related errors


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

Appendix: source

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

                    {
                        var typeDescriptor = TypeDescriptorFactory.Default.Find(currentObject.GetType());
                        if (typeDescriptor is ArrayDescriptor arrayDescriptor)
                        {
                            if (item.Value is not int)
                            {
                                throw new InvalidOperationException($"The path [{ToString()}] contains non-integer index on an array.");
                            }
                            int value = (int)item.Value;
                            memberPath.Push(arrayDescriptor, value);
                            currentObject = arrayDescriptor.GetValue(currentObject, value);
                        }
                        else if (typeDescriptor is CollectionDescriptor collectionDescriptor)
                        {
                            if (collectionDescriptor is SetDescriptor setDescriptor)
                            {
                                if (item.Value is null && !collectionDescriptor.ElementType.IsNullable())
                                {
                                    throw new InvalidOperationException($"The path [{ToString()}] contains a null item on a set.");
                                }
                                if (!setDescriptor.Contains(currentObject, item.Value))
                                {
                                    throw new InvalidOperationException($"The path [{ToString()}] item doesn't exsit on a set.");
                                }
                                memberPath.Push(setDescriptor, item.Value);
                                currentObject = item.Value;
                            }
                            else
                            {
                                if (item.Value is not int)
                                {
                                    throw new InvalidOperationException($"The path [{ToString()}] contains non-integer index on a collection.");
                                }
                                memberPath.Push(collectionDescriptor, item.Value);
                                currentObject = collectionDescriptor.GetValue(currentObject, item.Value);
                            }
                        }

View on GitHub (pinned to 96fad776d2)