stride3d/stride · error · YamlException

Unable to find class from tag

Error message

Unable to find class from tag [{0}]

What it means

PropertyKeyYamlSerializer.ConvertFrom parses a scalar of the form 'ClassName.PropertyName' to resolve a public static field (a PropertyKey) at deserialization time. It first resolves the class from the YAML tag via TypeFromTag; if no type is registered for the '!ClassName' tag, this YamlException is thrown.

Solutions

  1. Ensure the assembly containing the class is loaded and registered with the asset/serializer type system before deserializing
  2. Fix the class name in the YAML scalar or tag to match the current class name
  3. Restore the renamed/moved class or update all assets referencing the old tag
  4. Re-save the asset in the Stride editor so tags and class names are regenerated

Example fix

// before
MyProperty: !OldNamespaceOldClass.MyPropertyKey value
// after
MyProperty: !MyNamespaceMyClass.MyPropertyKey value
Defensive patterns

Strategy: try-catch

Try / catch

try { value = ConvertFrom(ref context, scalar); } catch (YamlException ex) when (ex.Message.StartsWith("Unable to find class")) { log.Error($"Missing type for tag {scalar.Value}: {ex.Message}"); throw; }

Prevention

When it happens

Trigger: Deserializing a YAML asset that references a PropertyKey whose class tag ('!' + className) is not found by the SerializerContext's tag registry — typically because the containing assembly is not loaded/scanned or the class was renamed/moved.

Common situations: Renaming or deleting a class containing PropertyKeys after assets referenced them; the plugin/assembly declaring the class not loaded at deserialization time; YAML tag aliases out of sync with the type registry after refactors.

Related errors


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Serializers/PropertyKeyYamlSerializer.cs:41

        }

        for (Type? t = type; t != null; t = t.BaseType)
            if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(PropertyKey<>))
                return true;

        return false;
    }

    public override object? ConvertFrom(ref ObjectContext objectContext, Scalar fromScalar)
    {
        var lastDot = fromScalar.Value.LastIndexOf('.');
        if (lastDot == -1)
            return null;

        var className = fromScalar.Value[..lastDot];

        var containingClass = objectContext.SerializerContext.TypeFromTag("!" + className, out var typeAliased)
            ?? throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to find class from tag [{0}]".ToFormat(className)); // Readd initial '!'

        var propertyName = fromScalar.Value[(lastDot + 1)..];
        var propertyField = containingClass.GetField(propertyName, BindingFlags.Public | BindingFlags.Static)
            ?? throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to find property [{0}] in class [{1}]".ToFormat(propertyName, containingClass.Name));
        return propertyField.GetValue(null);
    }

    protected override void WriteScalar(ref ObjectContext objectContext, ScalarEventInfo scalar)
    {
        // TODO: if ParameterKey is written to an object, It will not serialized a tag
        scalar.Tag = null;
        scalar.IsPlainImplicit = true;
        base.WriteScalar(ref objectContext, scalar);
    }

    public override string ConvertTo(ref ObjectContext objectContext)
    {
        var propertyKey = (PropertyKey)objectContext.Instance;

View on GitHub (pinned to 96fad776d2)