Sorry for the AI ticket, but it did a better job than I could:
Rendering a level sequence through Movie Render Queue crashes the editor with an EXCEPTION_ACCESS_VIOLATION when the scene contains a Niagara system using a GPU simulation target and the MRQ output format is EXR or PNG. The same render completes successfully with JPG output.
The crash is not in the image writer. It occurs in FNiagaraGpuComputeDispatch::ProcessPendingTicksFlush() — a safety-valve path that runs queued GPU simulation ticks against a fabricated dummy view outside the scene renderer. A Data Interface supplies a resource pointer that is not valid in that context; the D3D12 backend then makes a virtual call on it and jumps to address 0x1.
The output format matters only because of write latency. EXR (float, ~16 MB/frame) and 16-bit PNG stall the pipeline long enough for world ticks to accumulate without a corresponding scene render, crossing the tick-flush threshold. JPG finalizes fast enough to stay under it.
| Engine | 5.8.1-56057345 +++UE5+Release-5.8, Development Editor |
| OS | Windows 11 24H2 — 10.0.26100.9106 |
| GPU | NVIDIA RTX A6000, driver 596.72 (2026-06-10), D3D12 / SM6 |
| CPU / RAM | AMD Ryzen Threadripper PRO 3995WX (64-core) / 256 GB |
| Project | Flossing — level /Game/Test, sequence /Game/NewLevelSequence |
| Niagara system | /Game/EasyRain/System/Niagara/N_EasyRain_Niagara (GPU sim target) |
| MRQ | MovieGraph pipeline, Deferred renderer, beauty layer, 1920×1080, 1 camera, TileCount [1,1] |
Note: MRQ logs Using the default MovieGraphPipeline; the pipeline specified in Project Settings (MoviePipeline) is not compatible with graphs — the project-configured pipeline class is being silently ignored. Probably unrelated, but worth a look.
From the minidump exception stream:
ExceptionCode : 0xC0000005 EXCEPTION_ACCESS_VIOLATION ExceptionAddress : 0x0000000000000001 Info[0] : 8 -> EXECUTE (DEP) Info[1] : 0x0000000000000001
AccessType 8 is the important detail — this is an executed jump to 0x1, not a bad read. The address lies in no loaded module. That is an indirect call through a corrupt vtable pointer, i.e. a virtual call on a freed or never-initialised object.
RHI breadcrumbs (both configurations):
Breadcrumbs 'RDGExecute_RenderThread' - NiagaraGpuComputeDispatch - RenderGraphExecute - WorldTick
Nsight Aftermath was enabled (RHI.Aftermath true) and produced no GPU crash dump, confirming a CPU-side fault rather than a GPU fault or TDR. MemoryStats.bIsOOM = 0. Driver not denylisted.
Default configuration crashes on RHIThread, which loses the recording context and makes the bug very hard to attribute — the only Niagara frame is a template instantiated in the Niagara module:
D3D12RHI!SetShaderParametersOnContext() D3D12Commands.cpp:698 D3D12RHI!FD3D12CommandContext::RHISetShaderParameters() D3D12Commands.cpp:759 RHI!FRHICommandSetShaderParameters<FRHIComputeShader>::Execute() Niagara!FRHICommand<...SetShaderParameters<FRHIComputeShader>...>::ExecuteAndDestruct() RHI!FRHICommandListBase::Execute() RHI!FRHICommandListExecutor::FTranslateState::Translate_ExecuteCommandList() RenderCore!FRHIThread::Run()
Re-running with -norhithread -forcerhibypass moves the fault to RenderThread and exposes the recording site:
D3D12RHI!SetShaderParametersOnContext() D3D12Commands.cpp:698 D3D12RHI!FD3D12CommandContext::RHISetShaderParameters() D3D12Commands.cpp:759 Niagara!FRHIComputeCommandList::SetBatchedShaderParameters() RHICommandList.h:2631 Niagara!FNiagaraGpuComputeDispatch::DispatchStage'::<lambda_2>() NiagaraGpuComputeDispatch.cpp:1871 Niagara!TRDGLambdaPass<...>::Execute() RenderGraphPass.h:704 RenderCore!FRDGBuilder::ExecutePass() RenderGraphBuilder.cpp:3525 RenderCore!FRDGBuilder::ExecuteSerialPass() RenderGraphBuilder.cpp:3549 RenderCore!FRDGBuilder::Execute() RenderGraphBuilder.cpp:2157 Niagara!FNiagaraGpuComputeDispatch::ProcessPendingTicksFlush() NiagaraGpuComputeDispatch.cpp:521 Niagara!FNiagaraGpuComputeDispatch::Tick'::<lambda_1> RenderCore!ExecuteCommand() RenderingThread.cpp:1533 RenderCore!RenderingThreadMain() RenderingThread.cpp:261
Line attribution caveat: the lambda frame reports :1871 (DispatchComputeShader), but under bypass the preceding RHICmdList.SetBatchedShaderParameters(...) at :1869 is inlined into the same frame. The D3D12 frames confirm the fault is in the parameter set, not the dispatch.
FNiagaraGpuComputeDispatch::ProcessPendingTicksFlush() — NiagaraGpuComputeDispatch.cpp:385
When GPU ticks queue up without being consumed by a scene render, Tick fires a flush whose behaviour is selected by fx.Niagara.Batcher.TickFlush.Mode (default 1). The CVar's own help text documents the hazard:
fx.Niagara.Batcher.TickFlush.Mode (default 1)
0 = Keep ticks queued, can result in a long pause when gaining focus again.
1 = (Default) Process all queued ticks with dummy view / buffer data,
may result in incorrect simulation due to missing depth collisions, etc.
2 = Kill all pending ticks, may result in incorrect simulation due to
missing frames of data, i.e. a particle reset.
Mode 1 fabricates a view with a null render target (:474):
cpp
FSceneViewFamilyContext ViewFamily(
FSceneViewFamily::ConstructionValues(nullptr, GetSceneInterface(), FEngineShowFlags(ESFIM_Game))
.SetTime(CachedViewInitOptions.GameTime));
...
GetRendererModule().CreateAndInitSingleView(RHICmdList, &ViewFamily, &ViewInitOptions);
TConstStridedView<FSceneView> DummyViews = MakeStridedView<const FSceneView>(0, ViewFamily.Views[0], 1);
bIsOutsideSceneRenderer = true; // "Allow downstream logic to detect we are
// running pending ticks outside the scene renderer"
It then drives the full PreInitViews / PostInitViews / PostRenderOpaque chain against that dummy view. DispatchStage populates the batched parameters via SetShaderParameters(...) (:1866), which walks the shader parameter metadata including every Data Interface binding, and submits them at :1869. One of those bindings is invalid in the dummy-view context, and SetShaderParametersOnContext dereferences it.
The core defect: bIsOutsideSceneRenderer is only consulted in two places in the entire file (:1981 and :2143). It is never plumbed through to Data Interfaces, so a DI that binds a scene texture, depth buffer, or distance field has no way to detect the dummy-view context and bail out. The comment on :496 states the flag exists precisely so "downstream logic" can detect this — but downstream DI parameter population does not check it. The result is a corrupt pointer rather than the merely-incorrect simulation the CVar comment leads you to expect.
fx.Niagara.Batcher.TickFlush.MaxQueuedFrames default 3 fx.Niagara.Batcher.TickFlush.MaxPendingTicks default 10
Either crossing trips the flush (:405, :418). The MaxQueuedFrames help text says it is "generally only a concern when the application does not have focus" — the path was designed for a minimised editor, not for MRQ, which legitimately ticks the world without rendering every tick (warm-up frames, temporal sub-samples, and finalization).
Not alpha, and not bit depth — finalize/write duration. EXR and 16-bit PNG hold the pipeline long enough for ≥3 world ticks to elapse with no scene render, crossing MaxQueuedFrames. JPG does not. This also explains why the first crash landed exactly at MRQ's Moving to Finalize to finish writing items to disk — MRQ stops rendering the scene there while the world keeps ticking, so the threshold is crossed within a few frames.
10 for 10 on 2026-08-18 between 10:59 and 11:40, all with an identical signature. Crash GUIDs in Flossing/Saved/Crashes:
0BF6DEB74DCE9C7AB3F1528D7896E696 RHIThread 7D28BEFC49E34ABB06214E92DFDD13B8 RHIThread CA32B18048CB92979C8949B4F1D8B80F RHIThread 493E616E4BD781DFE0F03095951E1E4F RHIThread 6623D4FA464F18F9CED47EA9575F85D5 RHIThread 12BDB7D44C1E68A13674C48FA4370000 RHIThread 4E2B020A448915A91F9EF28233C0A07B RHIThread 7156B1F74D6994B31C5AA99A25EB1540 RHIThread DAB4A6DF4DB07931347BBBB81FD5C428 RHIThread B8737D1445050FC93078BBA71C33A599 RenderThread (-norhithread -forcerhibypass)
The default RHIThread stack is effectively undebuggable for this class of bug — the resource is bound on the render thread and dereferenced later on the RHI thread, so the recording context is gone. Relaunching with the following moves the fault to the recording site and was what made this diagnosable:
UnrealEditor.exe <Project>.uproject -norhithread -forcerhibypass
(-forcerhibypass — RHICommandList.cpp:1886. r.RHICmdBypass alone is a silent no-op while the RHI thread runs, because LatchBypass() at :1897 requires !IsRunningRHIInSeparateThread().)
Recommended — prevents the flush from firing during a render, keeps GPU particles and correct simulation:
fx.Niagara.Batcher.TickFlush.MaxQueuedFrames 100000 fx.Niagara.Batcher.TickFlush.MaxPendingTicks 100000
Confirms the diagnosis — avoids the dummy-view path entirely:
fx.Niagara.Batcher.TickFlush.Mode 0 # keep ticks queued fx.Niagara.Batcher.TickFlush.Mode 2 # discard pending ticks (visible particle reset)
Blunt — fx.NiagaraAllowGPUParticles 0. Avoids the crash but removes the GPU-simulated effect from the render entirely, so it is not viable for delivery.
[Link Removed]
[Link Removed]
[Link Removed]
[Link Removed]
[Link Removed]
To make the mechanism explicit rather than timing-dependent, lower the threshold so the flush fires reliably:
fx.Niagara.Batcher.TickFlush.MaxQueuedFrames 1
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-392456 in the post.
| 0 |
| Component | UE - Rendering - Architecture - Niagara |
|---|---|
| Affects Versions | 5.8.1 |
| Created | Aug 18, 2026 |
|---|---|
| Updated | Aug 20, 2026 |