stride3d/stride · error · ArgumentException

Binding describes an array larger than dataOuter

Error message

Binding describes an array larger than dataOuter ({dataOuter.Length} < {binding.Offset} + {binding.Count} * {(binding.Is32Bit ? 4 : 2)})

What it means

IndexBufferHelper wraps existing index buffer data for reading; the constructor validates that dataOuter is large enough to hold the binding's full view: Offset + Count * (2 or 4 bytes for 16/32-bit indices). If the array is smaller, ArgumentException is thrown with the exact sizes involved. This prevents out-of-range reads when interpreting mesh index data.

Solutions

  1. Pass the full buffer data array from FetchBufferContentOrThrow/TryFetchBufferContent for the same buffer the binding was built from.
  2. Verify binding.Offset and binding.Count against the actual data length before constructing.
  3. Check Is32Bit matches the buffer's actual index format (IndexBufferElementSize).

Example fix

// before
var helper = new IndexBufferHelper(binding, truncatedData, out var count);
// after
int required = binding.Offset + binding.Count * (binding.Is32Bit ? 4 : 2);
if (data.Length < required) throw new InvalidOperationException($"need {required} bytes, got {data.Length}");
var helper = new IndexBufferHelper(binding, data, out var count);
Defensive patterns

Strategy: validation

Validate before calling

int required = binding.Offset + binding.Count * (binding.Is32Bit ? 4 : 2);
if (dataOuter == null || dataOuter.Length < required)
    throw new InvalidOperationException($"Index data too small: need {required}, have {dataOuter?.Length ?? 0}");

Type guard

bool FitsBinding(IndexBufferBinding b, byte[] d) => d != null && d.Length >= b.Offset + b.Count * (b.Is32Bit ? 4 : 2);

Try / catch

try { var helper = new IndexBufferHelper(binding, data, out var count); }
catch (ArgumentException ex) { log.Error("index buffer data truncated", ex); }

Prevention

When it happens

Trigger: Constructing IndexBufferHelper (directly or via MeshExtension.AsReadable) with a byte[] shorter than binding.Offset + binding.Count * indexSize, e.g. reading from a truncated buffer, wrong vertex/index buffer mix-up, or a binding whose Count was computed for different data.

Common situations: Mesh assets whose buffer data was not fully loaded (stale AttachedReference length); offset/count mismatch after editing a mesh; reading a 32-bit index buffer with a 16-bit assumption or vice versa.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/IndexBufferHelper.cs:43

    public readonly byte[] DataOuter;
    public readonly IndexBufferBinding Binding;

    /// <summary>
    /// Effective index buffer, handles the binding offset
    /// </summary>
    public Span<byte> DataInner => DataOuter.AsSpan(Binding.Offset, Binding.Count * (Binding.Is32Bit ? 4 : 2));

    /// <inheritdoc cref="MeshExtension.AsReadable(IndexBufferBinding, IServiceRegistry, out IndexBufferHelper, out int)"/>
    public IndexBufferHelper(IndexBufferBinding binding, IServiceRegistry services, out int count) 
        : this(binding, MeshExtension.FetchBufferContentOrThrow(binding.Buffer, services), out count)
    {
    }

    /// <inheritdoc cref="MeshExtension.AsReadable(IndexBufferBinding, IServiceRegistry, out IndexBufferHelper, out int)"/>
    public IndexBufferHelper(IndexBufferBinding binding, byte[] dataOuter, out int count)
    {
        if (dataOuter.Length < binding.Offset + binding.Count * (binding.Is32Bit ? 4 : 2))
            throw new ArgumentException($"Binding describes an array larger than {nameof(dataOuter)} ({dataOuter.Length} < {binding.Offset} + {binding.Count} * {(binding.Is32Bit ? 4 : 2)})");

        DataOuter = dataOuter;
        Binding = binding;
        count = Binding.Count;
    }

    /// <summary>
    /// Branch to read the buffer as a 16 or 32 bit buffer, does not allocate
    /// </summary>
    /// <example>
    /// <code>
    /// if (Is32Bit(out var d32, out var d16))
    /// {
    ///     foreach (var value in d32)
    ///     {
    ///         // Your logic for 32 bit
    ///     }
    /// }

View on GitHub (pinned to 96fad776d2)