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
- Create the staging buffer without initial data and use a Copy staging/upload pattern: copy from a Default/Upload buffer, then read back.
- Switch Usage to Dynamic or Default if you need the buffer pre-populated with data.
- 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
- Treat Staging buffers as read-back only; seed data via a separate upload/Default buffer plus Copy.
- Use Dynamic or Default usage whenever initial data is required.
- Centralize buffer creation so usage/init-data combinations are checked in one place.
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
- Element size cannot be less or equal 0 for structured buffer
- Expecting a Buffer supporting UAV
- Copy region of staging resources is not supported yet
- Read / Write / ReadWrite is only supported for staging…
- The length of the destination data buffer is larger than…
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 stateView on GitHub (pinned to 96fad776d2)