stride3d/stride · error · ArgumentException

Offsets are only supported for Textures declared with

Error message

Offsets are only supported for Textures declared with {nameof(GraphicsResourceUsage)}.{nameof(GraphicsResourceUsage.Default)}

What it means

SetData supports a byte offset only when the buffer's usage is GraphicsResourceUsage.Default, because then it uses UpdateSubresource with a destination region. For other usages (Dynamic/Staging) the CPU-map path has no subresource region support, so any offsetInBytes > 0 throws ArgumentException. The message text literally leaks the {nameof(...)} placeholders unexpanded.

Solutions

  1. Use GraphicsResourceUsage.Default for the buffer when you need offset writes.
  2. Set offsetInBytes to 0 and upload the full data instead of a partial offset write.
  3. For partial updates of dynamic buffers, write the whole slab and use a constant-buffer offset in the shader, or create the buffer with Default usage.

Example fix

// before
dynamicBuffer.SetData(cmd, newData, offsetInBytes: 64); // throws
// after
defaultBuffer = Buffer.New<float>(device, count, BufferFlags.ConstantBuffer, GraphicsResourceUsage.Default);
defaultBuffer.SetData(cmd, newData, offsetInBytes: 64);
Defensive patterns

Strategy: validation

Validate before calling

if (offsetInBytes > 0 && buffer.Description.Usage != GraphicsResourceUsage.Default)
    throw new InvalidOperationException("Offset writes need Default usage");

Type guard

bool SupportsOffsetWrite(Buffer b) => b.Description.Usage == GraphicsResourceUsage.Default;

Try / catch

try { buffer.SetData(cmd, data, offsetInBytes); }
catch (ArgumentException ex) when (ex.Message.Contains("Offsets are only supported"))
{
    buffer.SetData(cmd, data, 0); // fall back to full write
}

Prevention

When it happens

Trigger: Calling buffer.SetData(commandList, data, offsetInBytes: N) with N > 0 on a buffer whose Description.Usage is Dynamic or Staging (e.g. a Dynamic constant or vertex buffer).

Common situations: Partially updating sub-ranges of a dynamic buffer with an offset; porting XNA/MonoGame code that used UpdateSubresource offsets onto a Staging or Dynamic buffer.

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/16e6fa119c101c8f. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Buffer.cs:514

            // If the Buffer is declared as Default usage, we can only use UpdateSubresource, which is not optimal but better than nothing
            if (Description.Usage == GraphicsResourceUsage.Default)
            {
                // Set up the dest region inside the Buffer
                if (Description.BufferFlags.HasFlag(BufferFlags.ConstantBuffer))
                {
                    commandList.UpdateSubResource(this, subResourceIndex: 0, fromDataAsBytes);
                }
                else
                {
                    var destRegion = new ResourceRegion(left: offsetInBytes, top: 0, front: 0, right: offsetInBytes + fromDataSizeInBytes, bottom: 1, back: 1);
                    commandList.UpdateSubResource(this, subResourceIndex: 0, fromDataAsBytes, destRegion);
                }
            }
            else
            {
                if (offsetInBytes > 0)
                    throw new ArgumentException("Offsets are only supported for Textures declared with {nameof(GraphicsResourceUsage)}.{nameof(GraphicsResourceUsage.Default)}", nameof(offsetInBytes));

                // Map the Buffer to CPU-writable memory
                var mappedResource = commandList.MapSubResource(this, subResourceIndex: 0, Usage == GraphicsResourceUsage.Staging ? MapMode.Write : MapMode.WriteDiscard);
                var toData = new Span<TData>((void*) mappedResource.DataBox.DataPointer, fromData.Length);
                fromData.CopyTo(toData);
                //Utilities.CopyWithAlignmentFallback((void*)mappedResource.DataBox.DataPointer, pointer, (uint)sizeInBytes);
                commandList.UnmapSubResource(mappedResource);
            }
        }

        #endregion

        /// <summary>
        ///   Creates a new <see cref="Buffer"/>.
        /// </summary>
        /// <param name="device">The <see cref="GraphicsDevice"/>.</param>
        /// <param name="description">The description of the Buffer.</param>
        /// <param name="viewFormat">

View on GitHub (pinned to 96fad776d2)