stride3d/stride · error · ArgumentException
Read / Write / ReadWrite is only supported for staging…
Error message
Read / Write / ReadWrite is only supported for staging resources
What it means
MapMode.Read, ReadWrite and Write on Direct3D12 require the resource to have been created with GraphicsResourceUsage.Staging, because they go through CPU-visible memory. Mapping a non-staging (e.g. Immutable/Default) resource with one of those modes throws ArgumentException naming the mapMode parameter.
Solutions
- Create the resource with GraphicsResourceUsage.Staging when you intend to Map it for Read/ReadWrite/Write.
- For readback, copy from the GPU resource to a staging resource with Copy first, then Map the staging resource in Read mode.
- Use MapMode.WriteDiscard on appropriate buffers instead of Write when rewriting whole contents (that path doesn't require staging).
- Check resource.Usage before mapping and branch accordingly.
Example fix
// before var buf = Buffer.New(GraphicsDevice, size); commandList.Map(buf, MapMode.Read, 0); // throws // after var staging = Buffer.New(GraphicsDevice, size, BufferFlags.None, GraphicsResourceUsage.Staging); commandList.Copy(buf, staging); var data = commandList.Map(staging, MapMode.Read, 0);
Defensive patterns
Strategy: validation
Validate before calling
if (mapMode is MapMode.Read or MapMode.ReadWrite or MapMode.Write
&& resource.Usage != GraphicsResourceUsage.Staging)
throw new ArgumentException("Create the resource with Staging usage for Read/Write maps", nameof(resource)); Type guard
static bool SupportsMapMode(GraphicsResource r, MapMode m) =>
m is not (MapMode.Read or MapMode.ReadWrite or MapMode.Write) || r.Usage == GraphicsResourceUsage.Staging; Try / catch
try { var mapped = commandList.Map(resource, MapMode.Read, 0); }
catch (ArgumentException) { /* copy to staging then map the staging copy */ } Prevention
- Create any resource you plan to Map with GraphicsResourceUsage.Staging.
- For readback of GPU data, Copy to a staging resource first.
- Prefer MapMode.WriteDiscard for whole-buffer rewrites on dynamic buffers.
When it happens
Trigger: Calling CommandList.Map with MapMode.Read/ReadWrite/Write on a Buffer or Texture whose Usage != GraphicsResourceUsage.Staging.
Common situations: Trying to read back GPU-written data from a default-usage buffer; forgetting to create the texture/buffer with GraphicsResourceUsage.Staging; porting D3D11 code where dynamic usage allowed similar mappings.
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
- D3D12: Staging buffers can't be created with initial data.
- Copy region of staging resources is not supported yet
- Only Buffers and Textures can be mapped
- Element size cannot be less or equal 0 for structured buffer
- NotImplementedException
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/fa9b702c4397d56a.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Direct3D12/CommandList.Direct3D12.cs:2253
// Internally it's a Buffer, so adapt resource index and offset
offsetInBytes = texture.ComputeBufferOffset(subResourceIndex, depthSlice: 0);
subResourceIndex = 0;
}
}
else if (resource is Buffer buffer)
{
usage = buffer.Usage;
if (lengthInBytes == 0)
lengthInBytes = buffer.SizeInBytes;
}
else throw new ArgumentException("Only Buffers and Textures can be mapped", nameof(resource));
if (mapMode is MapMode.Read or MapMode.ReadWrite or MapMode.Write)
{
// Is non-staging even possible for Read/Write?
if (usage != GraphicsResourceUsage.Staging)
throw new ArgumentException("Read / Write / ReadWrite is only supported for staging resources", nameof(mapMode));
}
// NOTE: This path is quite slow (it creates a new resource).
// Once we switch to D3D12 / Vulkan only, we should probably get rid of this use case
// by pooling and reusing buffers internally, or explicitly managed at the caller side
if (mapMode == MapMode.WriteDiscard)
{
// Mark old resource for deletion once Command List are executed
resource.OnDestroyed();
// Create new resource
resource.OnRecreate();
}
else if (mapMode != MapMode.WriteNoOverwrite) // Write / Read / ReadWrite
{
// Need to wait?
if (
// used in command list which hasn't be submitted yet? (only valid if our own, checked later)View on GitHub (pinned to 96fad776d2)