stride3d/stride · error · InvalidOperationException

Cannot modify a YamlAssetMetadata after it has been…

Error message

Cannot modify a YamlAssetMetadata after it has been attached.

What it means

YamlAssetMetadata.Set attaches metadata to a YAML path, but once the metadata object has been 'attached' (e.g. during asset processing/fixup), it becomes read-only. Any Set after attachment throws InvalidOperationException to protect invariants during path remapping.

Solutions

  1. Perform all Set calls before passing the metadata to Attach/asset processing
  2. Create a new YamlAssetMetadata<T> instance and copy values if post-attach mutation is needed
  3. Check isAttached (or expose an accessor) before mutating, and defer attachment until all writes are done
  4. In remapping code, build a fresh metadata dictionary and attach it once at the end

Example fix

// before
var meta = LoadAssetMetadata(); // already attached
meta.Set(path, value); // throws
// after
var meta = new YamlAssetMetadata<object>();
meta.Set(path, value);
meta.Attach(...);
Defensive patterns

Strategy: type-guard

Validate before calling

if (metadata.IsAttached) throw new InvalidOperationException("Attach metadata only after all Set calls");

Type guard

bool CanEdit<T>(YamlAssetMetadata<T> m) => !m.IsAttached; // expose or mirror isAttached

Try / catch

try { metadata.Set(path, value); }
catch (InvalidOperationException ex) { logger.Warn(ex, "Metadata already attached; change dropped"); }

Prevention

When it happens

Trigger: Calling Set on a YamlAssetMetadata<T> after Attach has run, e.g. during RemapIdentifiablePaths or in tests after the metadata was passed to the asset-processing pipeline.

Common situations: Game-editors/plugins trying to mutate asset metadata after loading/processing; unit tests caching a shared YamlAssetMetadata instance that was already used in serialization; two-phase asset import code that adds metadata late.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at sources/assets/Stride.Core.Assets/Yaml/YamlAssetMetadata.cs:55

public class YamlAssetMetadata<T> : IYamlAssetMetadata, IEnumerable<KeyValuePair<YamlAssetPath, T>>
{

    private readonly Dictionary<YamlAssetPath, T> metadata = new(YamlAssetPathComparer.Default);
    private bool isAttached;

    /// <summary>
    /// Gets the number of key/value pairs contained in the <see cref="YamlAssetMetadata{T}"/>
    /// </summary>
    public int Count => metadata.Count;

    /// <summary>
    /// Attaches the given metadata value to the given YAML path.
    /// </summary>
    /// <param name="path">The path at which to attach metadata.</param>
    /// <param name="value">The metadata to attach.</param>
    public void Set(YamlAssetPath path, T value)
    {
        if (isAttached) throw new InvalidOperationException("Cannot modify a YamlAssetMetadata after it has been attached.");
        metadata[path] = value;
    }

    /// <summary>
    /// Removes attached metadata from the given YAML path.
    /// </summary>
    /// <param name="path">The path at which to remove metadata.</param>
    public void Remove(YamlAssetPath path)
    {
        if (isAttached) throw new InvalidOperationException("Cannot modify a YamlAssetMetadata after it has been attached.");
        metadata.Remove(path);
    }

    /// <summary>
    /// Tries to retrieve the metadata for the given path.
    /// </summary>
    /// <param name="path">The path at which to retrieve metadata.</param>
    /// <returns>The metadata attached to the given path, or the default value of <typeparamref name="T"/> if no metadata is attached at the given path.</returns>

View on GitHub (pinned to 96fad776d2)