stride3d/stride · error · NotImplementedException

Unknown node type

Error message

Unknown node type

What it means

ErrorRecoverySerializer scans YAML parsing events to recover type/assembly tags from errored nodes; when the first node is neither a Mapping, Sequence nor Scalar it throws NotImplementedException('Unknown node type'). The recovery path simply has no handling for that node kind.

Solutions

  1. Fix the YAML source so the root node is a mapping, sequence, or scalar (remove root-level anchors/aliases)
  2. Re-export or regenerate the asset from Stride instead of repairing the YAML manually
  3. Check YamlDotNet/Stride version compatibility between the tool that wrote the asset and the reader
  4. Extend ErrorRecoverySerializer to handle the missing node kind if you own the pipeline

Example fix

# before (root alias, unsupported)
&base object

# after (plain mapping root)
root:
  Key: value
Defensive patterns

Strategy: validation

Validate before calling

using var parser = new YamlMappingNode(...); // ensure root is a mapping/sequence/scalar
if (doc.RootNode is YamlAliasNode) throw new InvalidOperationException("Root alias unsupported");

Type guard

bool HasSupportedRoot(YamlDocument doc) =>
    doc.RootNode is YamlMappingNode or YamlSequenceNode or YamlScalarNode;

Try / catch

try { return errorRecoverySerializer.ReadYaml(parser, expectedType); }
catch (NotImplementedException ex) { logger.Error(ex, "Unsupported YAML root node during error recovery"); return null; }

Prevention

When it happens

Trigger: ReadYaml encountering a YAML document whose first event is an anchor/alias or other exotic node type (not mapping, sequence, or scalar) during error recovery of a malformed asset.

Common situations: Corrupted or hand-edited Stride asset YAML containing aliases/anchors at the document root; a parser producing unexpected event streams after partial reads; assets saved by a newer Stride/YamlDotNet emitting node kinds the recovery code predates.

Related errors


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Yaml/ErrorRecoverySerializer.cs:90

                        tag = firstNode.Tag;

                    // Temporarily recreate the node without its tag, so that we can try deserializing as many members as possible still
                    // TODO: Replace this with switch pattern matching (C# 7.0)
                    if (firstNode is MappingStart mappingStart)
                    {
                        memoryParser.ParsingEvents[startPosition] = new MappingStart(mappingStart.Anchor, null, mappingStart.IsImplicit, mappingStart.Style, mappingStart.Start, mappingStart.End);
                    }
                    else if (firstNode is SequenceStart sequenceStart)
                    {
                        memoryParser.ParsingEvents[startPosition] = new SequenceStart(sequenceStart.Anchor, null, sequenceStart.IsImplicit, sequenceStart.Style, sequenceStart.Start, sequenceStart.End);
                    }
                    else if (firstNode is Scalar scalar)
                    {
                        memoryParser.ParsingEvents[startPosition] = new Scalar(scalar.Anchor, null, scalar.Value, scalar.Style, scalar.IsPlainImplicit, scalar.IsQuotedImplicit, scalar.Start, scalar.End);
                    }
                    else
                    {
                        throw new NotImplementedException("Unknown node type");
                    }
                }

                string? typeName = null;
                string? assemblyName = null;
                if (tag != null)
                {
                    var tagAsType = tag.StartsWith('!') ? tag[1..] : tag;
                    objectContext.SerializerContext.ParseType(tagAsType, out typeName, out assemblyName);
                }

                var log = objectContext.SerializerContext.Logger;
                log?.Warning($"Could not deserialize object of type '{typeName ?? tag}'; replacing it with an object implementing {nameof(IUnloadable)}", ex);

                var unloadableObject = UnloadableObjectInstantiator.CreateUnloadableObject(type, typeName, assemblyName, ex.Message, parsingEvents);
                objectContext.Instance = unloadableObject;
                objectContext.Descriptor = objectContext.SerializerContext.FindTypeDescriptor(unloadableObject.GetType());

View on GitHub (pinned to 96fad776d2)