stride3d/stride · error · InvalidOperationException

D3D12: Staging buffers can't be created with initial data.

Error message

D3D12: Staging buffers can't be created with initial data.

What it means

Thrown in Buffer.Recreate on D3D12 when a buffer with GraphicsResourceUsage.Staging is created together with initial data. Stride defines staging resources as read-back only (HeapType.Readback with CopyDest state), so providing initData contradicts that contract and the library throws InvalidOperationException.

Solutions

  1. Create the staging buffer without initial data and use a Copy staging/upload pattern: copy from a Default/Upload buffer, then read back.
  2. Switch Usage to Dynamic or Default if you need the buffer pre-populated with data.
  3. If data must start on the GPU, create an upload buffer with the data and CopyResource/CopyBufferRegion into the read-back buffer.

Example fix

// before
var buf = new Buffer(device, initData, size, BufferFlags.None, GraphicsResourceUsage.Staging);
// after
var buf = new Buffer(device, size, BufferFlags.None, GraphicsResourceUsage.Staging); // then CopyCommandList.Copy into it
Defensive patterns

Strategy: validation

Validate before calling

if (usage == GraphicsResourceUsage.Staging && hasInitData)
    throw new InvalidOperationException("Staging buffers are read-back only; do not pass initial data.");

Type guard

static bool IsStagingWithInitData(Buffer b, bool hasInitData) => b.Usage == GraphicsResourceUsage.Staging && hasInitData;

Try / catch

try { buf = new Buffer(device, initData, size, flags, GraphicsResourceUsage.Staging); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Staging")) { buf = new Buffer(device, size, flags, GraphicsResourceUsage.Staging); }

Prevention

When it happens

Trigger: Calling Buffer.New / setData-style constructors with Usage = GraphicsResourceUsage.Staging and non-empty init data, e.g. new Buffer(device, initialBytes, size, BufferFlags.None, GraphicsResourceUsage.Staging).

Common situations: Trying to pre-fill a read-back/staging buffer instead of creating an upload buffer, porting D3D11 code where staging with initial data was tolerated, or writing a GPU-readback helper that also seeds the buffer.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D12/Buffer.Direct3D12.cs:187

            if (bufferFlags.HasFlag(BufferFlags.ShaderResource))
                desiredResourceState |= ResourceStates.PixelShaderResource | ResourceStates.NonPixelShaderResource;

            if (bufferFlags.HasFlag(BufferFlags.StructuredBuffer))
            {
                if (bufferDescription.StructureByteStride <= 0)
                    throw new ArgumentException("Element size cannot be less or equal 0 for structured buffer");
            }

            if (bufferFlags.HasFlag(BufferFlags.ArgumentBuffer))
                desiredResourceState |= ResourceStates.IndirectArgument;

            var heapType = HeapType.Default;
            IsHostVisibleHeap = false;
            if (Usage == GraphicsResourceUsage.Staging)
            {
                // Per our own definition of staging resource (read-back only)
                if (hasInitData)
                    throw new InvalidOperationException("D3D12: Staging buffers can't be created with initial data.");

                heapType = HeapType.Readback;
                desiredResourceState = ResourceStates.CopyDest;
                IsHostVisibleHeap = true;
            }
            else if (Usage == GraphicsResourceUsage.Dynamic)
            {
                heapType = HeapType.Upload;
                desiredResourceState = ResourceStates.GenericRead;
                IsHostVisibleHeap = true;
            }

            // TODO: D3D12: Move to a global allocator in bigger committed resources
            var heap = new HeapProperties { Type = heapType };

            var initialResourceState = heapType != HeapType.Default ? desiredResourceState : ResourceStates.Common;

            // If the resource must be initialized with data, it is initially in the state

View on GitHub (pinned to 96fad776d2)