Slate Crash - FSlateBatchData::MergeRenderBatches

Hi folks,

I’m unsure how I’ve managed to come across this crash. I have had the 5.8 preview editor running for a couple of weeks now, but today it just seems to be blocked on this crash. The only thing of note I’ve really done recently is a full p4 clean, but in doing so I never cleaned my DDC. So I don’t think this is derived data related.

In the logs, there is a mention of a resource failing to load right as this exception is thrown. I’m not 100% sure they’re related. As it seems the asset that is being called out has never existed.

[2026.06.11-09.26.56:491][ 14]LogSlate: Could not load file for Slate resource: [../../../Engine/Plugins/Developer/Concert/ConcertApp/MultiUserClient/Content/icon_RemoveProperty_48x.png] file: [../../../Engine/Plugins/Developer/Concert/ConcertApp/MultiUserClient/Content/icon_RemoveProperty_48x.png]
Exception thrown: read access violation.
ShaderResource->**** was 0xFFFFFFFFFFFFFFD7.

I’m happy to have a discussion about this and work through any debugging required, and provide any extra info you think might help.

Many thanks,

David

EDIT: I believe the icon_RemoveProperty log is a red herring. Disabling optimisation and forcing no inline, I’m about to see that for the shader resource in question, it’s marked as “Destroyed”. Its DestroyState is set to 0x84. I wonder if this is a multi-thread issue?

EDIT2: More firmly believing that this is a multi-threading issue now. I logged out every call to ~FSlateShaderResource and the THIS pointer for each, and right before the exception is thrown I can see the resource in question being destructed.

[2026.06.12-08.47.31:084][ 13]LogTemp: FSlateShaderResource::~FSlateShaderResource 0000015C27E4E920
[2026.06.12-08.47.31:084][ 13]LogTemp: FSlateShaderResource::~FSlateShaderResource 0000015C27E4E740
[2026.06.12-08.47.31:084][ 13]LogTemp: FSlateShaderResource::~FSlateShaderResource 0000015BFCB9CE80
[2026.06.12-08.47.31:108][ 13]LogSlate: Could not load file for Slate resource: [../../../Engine/Plugins/Developer/Concert/ConcertApp/MultiUserClient/Content/icon_RemoveProperty_48x.png] file: [../../../Engine/Plugins/Developer/Concert/ConcertApp/MultiUserClient/Content/icon_RemoveProperty_48x.png]
Exception thrown: read access violation.
ShaderResource->**** was 0xFFFFFFFFFFFFFFD7.

[Image Removed]EDIT3: This appears to have something to do with the asset registry cache. I debugged back to finding one source that causes resources to be flushed (in this case UserToolboxSubsystem::OnAssetChanged->RefreshIcons), which got me past my initial crash. Only for the crash to occur 30 seconds later when something else caused resources to be deleted. Booting the editor afterwards though however seems stable. I do definitely believe there is an unsafe resource usage occurring since one part of the engine can delete all the resources without telling the Batch systems.

[Attachment Removed]

Steps to Reproduce

  • Launch the editor for a project that utilises the UserToolbox plugin with custom icons
  • Ensure there is no CachedAssetRegistry of any kind, legacy format or current format
  • Observe that once FUserToolBoxStyle::ReloadTextures() is called, the ElementBatcher will be unable to complete the merge task because the ShaderResources have been deleted. Confirmed by the delete flag being 0x84.
    [Attachment Removed]

Hi,

So sorry for the delay, we had quite a few folks away this past week for Unreal Fest. It sounds like you’ve at least gotten to a point where you can run the editor and are no longer blocked? Do you still have a way to reproduce this if needed?

My best guess at a “cause” is CL#52789518 which removed editor throttling during asset compilation, and this revealed some underlying problem with how the asset manager is accessing Slate resources by allowing multiple calls to ReloadTextureResources in parallel. Are all the crashes you see related to the UserToolbox plugin, or did the later crash occur in some other module? If it’s fully contained to the UserToolbox plugin, we may be able to avoid this by guarding against reentrancy in FSlateRHIResourceManager::ReloadTextures:

void FSlateRHIResourceManager::ReloadTextures()
{
	checkSlow( IsThreadSafeForSlateRendering() );
 
	// Guard against reentrancy
	if (bReloadTexturesInProgress)
		return;
	TGuardValue<bool> ReloadGuard(bReloadTexturesInProgress, true);

If you have a solid repro case and want to give that a try, I can run it by the team to see if there are any side effects I’m not thinking about.

Best,

Cody

[Attachment Removed]

I have a potential workaround that seems to be holding things together for me at present.

After the Rendered->ReloadTextureResources() call, I’m calling to the SlateApp to flush render state.

void FUserToolBoxStyle::ReloadTextures()
{
	if (FSlateApplication::IsInitialized())
	{
		if (auto Renderer = FSlateApplication::Get().GetRenderer())
		{
			Renderer->ReloadTextureResources();
 
			// @CHANGE BEGIN: Invalidate all widgets and increment FSlateRHIRenderer::ResourceVersion causing all caches to get invalidated. Thus stopping the crash caused by a cache accessing deleted resources.
			FSlateApplication::Get().FlushRenderState();
			// @CHANGE END.
		}
	}
}

The thinking here is, as pointed out in my comment that I’m just trying to nuke as many caches as I can. And this seems to have caught the ElementBatcher caches of shader resources. Eliminating the crash.

Many thanks,

David

[Attachment Removed]

Hi,

Thanks for continuing to chase this down while we were on break! It feels a bit hacky to force a flush after reloading texture resources (and it doesn’t seem like we do that anywhere else), but the UserToolbox might be enough of a special case to require it. I haven’t worked with this plugin too much, but the Icon Tracker setup could be responsible since it operates on uassets that the registry is still loading as part of the editor startup (where other editor icons are typically just textures that won’t exist in the content folder). The UserToolboxSubsystem in particular registers to some Asset Registry callbacks to do additional asset registry operations, which seems to violate some assumptions about the state of the cache. Basically, the issue may be reentrancy at the Asset Registry level and not at the FSlateRHIResourceManager level.

Another idea that might avoid any negative performance impact from flushing everything would be to defer UUserToolboxSubsystem::RefreshIcons until the end of the frame. We’d need to update all of the callsites to instead register a delegate to FCoreDelegates::OnEndFrame, and then make that delegate do the actual refresh before unregistering itself. I can put together a CL to test if you want to give that a try, unless you’re happy with your current workaround.

[Attachment Removed]

Dug a little deeper still after your recommendation.

I first intersected all the calls to FUserToolBoxStyle::ReloadTextures and added that delegate as you suggested. I caught two cases, one in UserToolBoxStyle.cpp and one in UserToolBoxSubsystem.cpp. I replaced those with:

void UUserToolboxSubsystem::OnAssetChanged(const FAssetData& InAssetData)
{
	if (InAssetData.AssetClassPath != UIconsTracker::StaticClass()->GetClassPathName())
	{
		return;
	}
 
	UIconsTracker* Asset = Cast<UIconsTracker>(InAssetData.GetAsset());
	if (IsValid(Asset))
	{
		//RefreshIcons();
		check(!OnEndFrameHandle.IsValid());
		OnEndFrameHandle = FCoreDelegates::OnEndFrame.AddLambda([this]()
			{
				RefreshIcons(); 
				FCoreDelegates::OnEndFrame.Remove(OnEndFrameHandle);
				OnEndFrameHandle.Reset();
			});
	}
}

The other call within Style.cpp differs slightly because everything in that is static but follows the same structure.

Unfortunately it didn’t fix the crash.

I tried to make the call less async by calling FinishMerge within the StartMerge call:

void FSlateWindowElementList::StartMergeRenderBatches()
{
	if (!BatchData.GetRenderBatches().IsEmpty() || !BatchDataHDR.GetRenderBatches().IsEmpty())
	{
		MergeBatchDataTask = UE::Tasks::Launch(TEXT("Slate::MergeRenderBatches"), [this]
		{
			TRACE_CPUPROFILER_EVENT_SCOPE(Slate::MergeRenderBatches);
			BatchData.MergeRenderBatches();
			BatchDataHDR.MergeRenderBatches();
		});
		FinishMergeRenderBatches(); // <----
	}
}

And then got the following callstack on the very next frame after ReloadTextures was called:

>	UnrealEditor-SlateCore.dll!FSlateBatchData::MergeRenderBatches() Line 249	C++
 	UnrealEditor-SlateCore.dll!FSlateWindowElementList::StartMergeRenderBatches::__l5::<lambda_1>::operator()() Line 91	C++
 	UnrealEditor-Core.dll!UE::Tasks::Private::FTaskBase::TryExecuteTask() Line 524	C++
 	UnrealEditor-Core.dll!UE::Tasks::Private::FTaskBase::TryRetractAndExecute(UE::FTimeout Timeout, unsigned int RecursionDepth) Line 159	C++
 	UnrealEditor-Core.dll!UE::Tasks::Private::FTaskBase::WaitImpl(UE::FTimeout Timeout) Line 255	C++
 	UnrealEditor-Core.dll!UE::Tasks::Private::FTaskBase::Wait() Line 219	C++
 	[Inline Frame] UnrealEditor-SlateCore.dll!UE::Tasks::Private::FTaskHandle::Wait() Line 74	C++
 	[Inline Frame] UnrealEditor-SlateCore.dll!FSlateWindowElementList::FinishMergeRenderBatches() Line 99	C++
 	UnrealEditor-SlateCore.dll!FSlateWindowElementList::StartMergeRenderBatches() Line 93	C++
 	UnrealEditor-SlateCore.dll!FSlateElementBatcher::AddElements(FSlateWindowElementList & WindowElementList) Line 350	C++
 	UnrealEditor-SlateRHIRenderer.dll!FSlateRHIRenderer::DrawWindows_Private(FSlateDrawBuffer & WindowDrawBuffer) Line 1633	C++
 	UnrealEditor-Slate.dll!FSlateApplication::PrivateDrawWindows(TSharedPtr<SWindow,1> DrawOnlyThisWindow) Line 1530	C++
 	UnrealEditor-Slate.dll!FSlateApplication::DrawWindows() Line 1211	C++
 	UnrealEditor-Slate.dll!FSlateApplication::TickAndDrawWidgets(float DeltaTime) Line 1820	C++
 	UnrealEditor-Slate.dll!FSlateApplication::Tick(ESlateTickType TickType) Line 1666	C++
 	UnrealEditor.exe!FEngineLoop::Tick() Line 6003	C++
 	[Inline Frame] UnrealEditor.exe!EngineTick() Line 60	C++
 	UnrealEditor.exe!GuardedMain(const wchar_t * CmdLine) Line 190	C++
 	UnrealEditor.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 266	C++
 	UnrealEditor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 338	C++
 	[Inline Frame] UnrealEditor.exe!invoke_main() Line 102	C++
 	UnrealEditor.exe!__scrt_common_main_seh() Line 288	C++
 	kernel32.dll!00007ff86ef2e957()	Unknown
 	ntdll.dll!00007ff8706e7c1c()	Unknown

This bug is very wriggly! :slight_smile:

It feels like we need some way to clear the CurBatch.ShaderResource pointer when we reload in this circumstance. At this point I need to admit I’m not 100% sure what makes this circumstance special, aside from “cache isn’t present”. By that I mean I’m not sure why this same code doesn’t cause a crash when the cache is present and accounted for. Perhaps that’s my next step.

Many thanks,

David

[Attachment Removed]

Hi,

I managed to get the MergeRenderBatches crash to repro, but only when I set up a new IconTracker. I also saw a crash in FSlateStyleSet on shutdown, so I’m definitely suspicious of how this plugin is managing the lifetime of the brushes it makes for those icons. Deleting the asset registry didn’t seem to cause another crash, but things like this tend to hide themselves in simpler test projects (especially since the asset registry will finish it’s scan quite early).

It appears there was an attempt to fix this at CL#51858374, but since I’ve been able to reproduce the issue in main I’ve reopened that ticket (UE-365361).

An easy option that might suffice for now would be to just get rid of the call to FUserToolBoxStyle::ReloadTextures entirely. Textures should be lazy-loaded in general, and while this would mean that external edits wouldn’t be picked up automatically, the UserToolbox.RefreshIcons console command could still be used to manually reload everything. That seems to work for my specific repro, does it cause any problems on your end?

[Attachment Removed]

Hi,

I checked in a handful of fixes (the two crashes here, plus a few other minor issues I ran into) at CL# 55830941. My test scenario was fairly basic, so if you’d want to backport that and see how it goes, I’d be interested in hearing if you still run into any issues. Thanks for all the legwork on your end, hopefully we’ve got the UserToolBox plugin in a better place now!

[Attachment Removed]

Hi Cody, thanks for your reply.

I had a solid repro last week, however in attempting to try again just now it appears to be behaving itself. Typical. :slight_smile:

I’ll keep trying and then if i hit it again I’ll throw in your workaround and report back.

It does appear that UserToolbox was the plugin it surfaced in, but I’m not completely confident in saying that it’s the sole source of the problem.

Will report back when I have more info.

Many thanks,

David

[Attachment Removed]

Got my repro back, threw in the potential workaround and it didn’t resolve the crash.

I remembered that I can repro this 100% when I delete the Intermediate/CachedAssetRegistry folder. Luckily I kept a back up so I can just restore that. Going to dig a little more to see if I can’t find more info for us.

David

[Attachment Removed]

I can at least rule out the editor throttling as the cause, since that doesn’t appear to have made it into 5.8.0. The version of the file we have still has the throttling code that CL removes, present.

[Attachment Removed]

Ping to keep this ticket open over the Epic break

Dug a little bit further into this, it is definitely something to do with a clean boot of the editor in a project that utilises the UserToolBox and custom icons. I can work around it by removing commenting out the contents of FUserToolBoxStyle::ReloadTextures(), loading the editor, allowing a CachedAssetRegistry to be generated, and then re-adding the contents of that function.

At this point, I’ve tried to introduce a new CriticalSection to stop that function and the Merge task from being able to overlap, but that didn’t seem to work unfortunately. Still trying some more solutions and will hopefully report back with a working one soon.

Many thanks,

David

[Attachment Removed]

Hi Cody!

I have full acceptance that this is definitely a sledgehammer to crack a walnut. :grin: It was definitely a case of “this is one of our last integration blocking bugs, can I just stabilise things and massage it later”.

I would definitely appreciate a CL to attempt a more refined fix if you’re able to offer it.

Many thanks,

David

[Attachment Removed]

Hey Cody,

That’s cool that we both have repro steps for it now. Sorry I couldn’t provide a sample project. Things are manic here. :slight_smile:

I also noticed that crash on shutdown too. I had another EPS ticket with that where I tendered a workaround. I noticed that there’s an collection of TUniquePtrs that is also being manually copied into another collection in another class. That class then calls delete on shutdown.

I had actually observed that not calling ReloadTextures stopped the crash from occurring as well. I wasn’t too keen on it purely just because I wasn’t sure what the consequences may be. I was honestly tempted to do a check to see if the Intermediate/Cache… folder was in place before calling it. Which I may still do. I’ll admit that’s also quite hacky but hey if it gets us through.

Many thanks,

David

[Attachment Removed]