stride3d/stride · error · InvalidOperationException

A MaterialPass can only belong to a single Material

Error message

A MaterialPass can only belong to a single Material

What it means

MaterialPassCollection.InsertItem enforces that each MaterialPass belongs to exactly one Material. When inserting a pass whose Material property is already set to another material, it throws InvalidOperationException to prevent sharing a pass between materials.

Solutions

  1. Create a new MaterialPass instance for the second material instead of reusing the pass
  2. If sharing is intentional, clone the pass and copy its relevant properties
  3. Clear the pass's Material reference before reassigning only if you truly intend to move it (remove it from the first material first)

Example fix

// before: reusing the same pass in two materials
materialA.Passes.Add(pass);
materialB.Passes.Add(pass); // throws
// after: give each material its own pass
materialA.Passes.Add(pass);
materialB.Passes.Add(new MaterialPass { BlendStates = pass.BlendStates, ... });
Defensive patterns

Strategy: validation

Validate before calling

if (pass.Material != null && pass.Material != targetMaterial)
    pass = ClonePass(pass); // create a copy before adding
targetMaterial.Passes.Add(pass);

Type guard

bool IsUnowned(MaterialPass p) => p.Material == null;

Prevention

When it happens

Trigger: Adding the same MaterialPass instance (e.g. grabbed from another material's Passes collection or reused from a cached pass) into a second material's Passes list.

Common situations: Sharing a pass between two materials to save memory; caching passes and re-adding them to newly built materials; copying passes by reference instead of cloning.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Rendering/Rendering/MaterialPassCollection.cs:26

{
    /// <summary>
    /// A collection of <see cref="MaterialPass"/>.
    /// </summary>
    [DataSerializer(typeof(ListAllSerializer<MaterialPassCollection, MaterialPass>))]
    public sealed class MaterialPassCollection : FastCollection<MaterialPass>
    {
        private readonly Material material;

        internal MaterialPassCollection(Material material)
        {
            this.material = material;
        }

        /// <inheritdoc/>
        protected override void InsertItem(int index, MaterialPass item)
        {
            if (item.Material != null)
                throw new InvalidOperationException($"A {nameof(MaterialPass)} can only belong to a single {nameof(Material)}");

            base.InsertItem(index, item);
            item.Material = material;
        }

        /// <inheritdoc/>
        protected override void RemoveItem(int index)
        {
            this[index].Material = null;
            base.RemoveItem(index);
        }

        /// <inheritdoc/>
        protected override void SetItem(int index, MaterialPass item)
        {
            // Note: Changing CollectionChanged is not thread-safe
            var oldItem = this[index];
            if (oldItem != null)

View on GitHub (pinned to 96fad776d2)