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
- Perform all Set calls before passing the metadata to Attach/asset processing
- Create a new YamlAssetMetadata<T> instance and copy values if post-attach mutation is needed
- Check isAttached (or expose an accessor) before mutating, and defer attachment until all writes are done
- 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
- Batch all metadata writes before attaching
- Never cache shared YamlAssetMetadata instances across loads
- Copy entries into a new instance if post-attach edits are needed
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
- Could not find asset
- Expect name1=value1;name2=value2 format.
- An IObjectNode was expected when processing the path
- An IMemberNode was expected when processing the path
- Unable to load the given stream
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)