stride3d/stride · error · ArgumentNullException

commandLists

Error message

commandLists

What it means

Standard ArgumentNullException guard in GraphicsDevice.ExecuteCommandLists: the commandLists array argument is null. Vulkan submission needs an array of CompiledCommandList to build VkCommandBufferSubmitInfo entries.

Solutions

  1. Pass a valid CompiledCommandList[] (may be empty but not null)
  2. Ensure the frame's command lists are recorded before submission
  3. Check that your render pipeline always allocates the array before calling ExecuteCommandLists

Example fix

// before
GraphicsDevice.ExecuteCommandLists(2, null);
// after
var lists = new CompiledCommandList[] { cmdListA, cmdListB };
GraphicsDevice.ExecuteCommandLists(lists.Length, lists);
Defensive patterns

Strategy: validation

Validate before calling

if (commandLists is null)
    throw new InvalidOperationException("No command lists recorded for this frame.");
GraphicsDevice.ExecuteCommandLists(commandLists.Length, commandLists);

Type guard

if (commandLists is not CompiledCommandList[] lists || lists.Length == 0)
    return;

Try / catch

try
{
    GraphicsDevice.ExecuteCommandLists(count, commandLists);
}
catch (ArgumentNullException ex)
{
    Logger.Error(ex, "Attempted to submit null command list array.");
}

Prevention

When it happens

Trigger: Calling graphicsDevice.ExecuteCommandLists(count, null) directly or via a renderer path that failed to build the frame's command list array.

Common situations: Custom render pipelines that skip CommandList recording; miswired render-system code passing an uninitialized array; mocking/unit-test code calling the API directly.

Related errors


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

Appendix: source

Thrown at sources/engine/Stride.Graphics/Vulkan/GraphicsDevice.Vulkan.cs:305

        }

        /// <summary>
        /// Executes a deferred command list.
        /// </summary>
        /// <param name="commandList">The deferred command list.</param>
        public void ExecuteCommandList(CompiledCommandList commandList)
        {
            ExecuteCommandListInternal(commandList);
        }

        /// <summary>
        /// Executes multiple deferred command lists.
        /// </summary>
        /// <param name="count">Number of command lists to execute.</param>
        /// <param name="commandLists">The deferred command lists.</param>
        public unsafe void ExecuteCommandLists(int count, CompiledCommandList[] commandLists)
        {
            if (commandLists == null) throw new ArgumentNullException(nameof(commandLists));
            if (count > commandLists.Length) throw new ArgumentOutOfRangeException(nameof(count));

            var commandBufferInfos = stackalloc VkCommandBufferSubmitInfo[count];
            for (int i = 0; i < count; i++)
                commandBufferInfos[i] = CommandBufferSubmit(commandLists[i].NativeCommandBuffer);

            ulong nextCommandListFenceValue;
            lock (QueueLock)
            {
                var commandListFenceValue = CommandListFence.NextFenceValue++;
                nextCommandListFenceValue = commandListFenceValue + 1;
                // Make sure all copies are done as well
                var copyFenceValue = CopyFence.NextFenceValue;

                var waitInfos = stackalloc VkSemaphoreSubmitInfo[]
                {
                    SemaphoreSubmit(CommandListFence.Semaphore, commandListFenceValue),
                    SemaphoreSubmit(CopyFence.Semaphore, copyFenceValue),

View on GitHub (pinned to 96fad776d2)