stride3d/stride · error · InvalidOperationException
Invalid state for
Error message
Invalid state for {resource.CommandListFenceValue} What it means
After confirming no other unsubmitted command list owns the staging resource, Map expects a recorded CommandListFenceValue to wait on. If it is null, internal state is inconsistent (no fence value was recorded for the last submission), so the code throws InvalidOperationException with the interpolated value.
Solutions
- Ensure the staging resource was last written via CommandList.Update on a properly submitted command list so the fence value is recorded.
- Don't manually clear/reset resource.CommandListFenceValue or device fences in application code.
- Recreate the staging resource if its tracking state is suspected corrupt.
- If reproducible with straightforward API usage, report as an engine bug (this is an internal invariant).
Example fix
// before resource.CommandListFenceValue = null; // manual clearing corrupts state commandList.Map(resource, MapMode.Read, 0); // throws // after // let the engine manage fence values; update then map: commandList.Update(resource, data); commandList.Flush(); commandList.Map(resource, MapMode.Read, 0);
Defensive patterns
Strategy: try-catch
Validate before calling
if (resource.CommandListFenceValue is null && resource.UpdatingCommandList is null)
{
// no tracked submission: refresh state by recreating or re-uploading the resource
} Try / catch
try { commandList.Map(stagingResource, MapMode.Read, 0); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Invalid state"))
{ /* fence bookkeeping corrupt: recreate resource or re-run Update path */ } Prevention
- Always write staging resources through CommandList.Update so fence values are tracked.
- Never manually mutate CommandListFenceValue or device fences from app code.
- Treat this as an engine invariant violation: report reproducible cases upstream.
When it happens
Trigger: Mapping a staging resource whose last updating command list was submitted but for which CommandListFenceValue was never set — typically after misuse of low-level flush APIs, resetting fences manually, or skipping the normal Update path that records the fence value.
Common situations: Custom render-loop code that submits command lists directly without going through the resource-tracking helpers; resource reused across device resets/recreation where fence bookkeeping was cleared; engine-level bugs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- CommandList updating the staging resource has not been…
- ArgumentNullException (targetProfiles)
- Cannot copy data between Buffers and Textures.
- Cannot copy data between GraphicsResources of types
- Copy region from staging texture is not supported yet
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/415835971a7fcce6.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Direct3D12/CommandList.Direct3D12.cs:2289
// used in command list which hasn't be submitted yet? (only valid if our own, checked later)
resource.UpdatingCommandList is not null
// updated in a previous command list which hasn't be finished yet
|| (resource.CommandListFenceValue is not null && !GraphicsDevice.CommandListFence.IsFenceCompleteInternal(resource.CommandListFenceValue.Value)))
{
if (doNotWait)
{
return new MappedResource(resource, subResourceIndex, dataBox: default);
}
if (resource.UpdatingCommandList == this)
// Need to flush? (check if part of current Command List)
// resource.CommandListFenceValue should be set after
FlushInternal(wait: false);
else if (resource.UpdatingCommandList is not null)
throw new InvalidOperationException("CommandList updating the staging resource has not been submitted");
if (resource.CommandListFenceValue is null)
throw new InvalidOperationException($"Invalid state for {resource.CommandListFenceValue}");
GraphicsDevice.CommandListFence.WaitForFenceCPUInternal(resource.CommandListFenceValue.Value);
// We're now up to date, remove command list fence value (if any)
resource.CommandListFenceValue = null;
}
}
// Also make sure all copy queues are done
// (important for all cases, since it uploads initial data and also set resource barrier)
if (resource.CopyFenceValue.HasValue)
{
GraphicsDevice.CopyFence.WaitForFenceCPUInternal(resource.CopyFenceValue.Value);
resource.CopyFenceValue = null;
}
scoped ref var fullRange = ref NullRef<D3D12Range>();
View on GitHub (pinned to 96fad776d2)