stride3d/stride · error · ArgumentException

The length of the destination buffer

Error message

The length of the destination buffer ({destLengthInBytes} bytes) is not compatible with the expected largestSize ({mipMapSize} bytes) : Width * Height * Depth * sizeof(Format) largestSize in bytes

What it means

When reading texture data back (the GetData path copying from a staging texture), the destination buffer in bytes must not exceed the mip level's total size (Width * Height * Depth * sizeof(Format), i.e. MipmapSize). ArgumentException is thrown when destLengthInBytes > mipMapSize, meaning the buffer cannot correspond to this mip level.

Solutions

  1. Allocate the destination buffer for the requested mip: width*height*depth * Format.SizeInBytes bytes.
  2. Pass the correct mipLevel so mipMapSize matches the buffer you provide.
  3. Slice a larger scratch buffer to the exact mip size before calling GetData.

Example fix

// before
var big = new byte[width * height * 4]; // sized for mip 0
texture.GetData(commandList, big, mipLevel: 2); // throws: too large for mip 2
// after
var mip = texture.GetMipMapDescription(2);
var buf = new byte[mip.Width * mip.Height * mip.Depth * texture.Format.SizeInBytes];
texture.GetData(commandList, buf, mipLevel: 2);
Defensive patterns

Strategy: validation

Validate before calling

var mip = texture.GetMipMapDescription(mipLevel);
int required = mip.MipmapSize;
int provided = dest.Length * sizeof(T);
if (provided > required)
    throw new InvalidOperationException($"Dest buffer {provided}B exceeds mip size {required}B");

Type guard

static bool BufferFitsMip<T>(Texture t, T[] buf, int mipLevel) where T : unmanaged => buf.Length * sizeof(T) <= t.GetMipMapDescription(mipLevel).MipmapSize;

Try / catch

try { texture.GetData(commandList, dest, mipLevel: lvl); }
catch (ArgumentException ex)
{
    logger.LogError(ex, "Buffer {Len}B incompatible with mip {Mip}", dest.Length * sizeof(byte), lvl);
    throw;
}

Prevention

When it happens

Trigger: Calling GetData with a destination array larger than the mip level's MipmapSize (e.g. reusing a buffer sized for mip 0 to read mip 2, or an oversized generic scratch array).

Common situations: Reading individual mip levels into a shared scratch buffer sized for the largest mip; CPU readback of textures whose format size was estimated incorrectly.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Texture.cs:1249

        ///   at <paramref name="arrayIndex"/> and <paramref name="mipLevel"/>.
        /// </exception>
        public unsafe bool GetData<T>(CommandList commandList, Texture stagingTexture, Span<T> toData, int arrayIndex = 0, int mipLevel = 0, bool doNotWait = false) where T : unmanaged
        {
            ArgumentNullException.ThrowIfNull(stagingTexture);

            // Get a description for the specified mip-level
            ref readonly var mipmap = ref GetMipMapDescription(mipLevel);

            int height = mipmap.HeightPacked;
            int depth = mipmap.Depth;
            int rowStride = mipmap.RowStride;
            int textureDepthStride = mipmap.DepthStride;
            int mipMapSize = mipmap.MipmapSize;

            int destLengthInBytes = toData.Length * sizeof(T);

            if (destLengthInBytes > mipMapSize)
                throw new ArgumentException($"The length of the destination buffer ({destLengthInBytes} bytes) is not compatible with " +
                    $"the expected largestSize ({mipMapSize} bytes) : Width * Height * Depth * sizeof(Format) largestSize in bytes");

            // Copy the actual content of the texture to the staging Resource
            if (!ReferenceEquals(this, stagingTexture))
                commandList.Copy(this, stagingTexture);

            int subResourceIndex = GetSubResourceIndex(arrayIndex, mipLevel);

            // Map the staging Resource to CPU-accessible memory
            var mappedResource = commandList.MapSubResource(stagingTexture, subResourceIndex, MapMode.Read, doNotWait);

            // Box can be empty if `doNotWait` is true: Return false if empty
            var box = mappedResource.DataBox;
            if (box.IsEmpty)
                return false;

            // If depth == 1 (like for 1D, 2D, or Cube), then depthStride is not used
            var boxDepthStride = Depth == 1 ? box.SlicePitch : textureDepthStride;

View on GitHub (pinned to 96fad776d2)