Description

When a texture asset has certain properties edited, its PostEditChangeProperty() method calls to UTexture::NotifyMaterials(), which triggers a recompilation of materials that reference it in their material graph. This includes preview materials created by the "Start Previewing Node" feature, which apparently are kept around while the Material Editor window is open, after the preview was stopped. In that situation, the compilation of the preview material attempts to process the Texture Sample node, but at that time the cached "ReferencedTextures" of that preview material is empty. This results in an error, a check() failure, and finally a crash, as shown below and in the provided call stacks.

[Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.cpp]
FHLSLMaterialTranslator::Texture()

  • Error: "Compiler->Texture() failed to find texture '%s' in referenced list of size '%i':"
  • checkf(): "Material expression called Compiler->Texture() without implementing UMaterialExpression::GetReferencedTexture properly"

[Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.cpp]
FHLSLMaterialTranslator::TextureSample()

  • Crash (Array out-of-bounds): Material->GetReferencedTextures()[TextureExpression->GetTextureIndex()]

This crash has been observed in all versions from at least 4.27. Some specific situations that trigger UTexture::NotifyMaterials() and result in the crash:

  • When one of the following properties is changed in the texture editor:
  • AddressX (X-axis Tiling Method)
  • AddressY (Y-axis Tiling Method)
  • CompressionSettings
  • Filter
  • LODGroup
  • Srgb
  • CompressionQuality
  • VirtualTextureStreaming
  • When any property is changed in the texture editor, if some of its current settings are invalid. For example:
  • Texture flagged as a virtual texture but virtual texturing is globally disabled
  • Texture flagged as a virtual texture but is not power-of-two
  • Texture flagged as a virtual texture but is on the "Color Lookup Table" LOD group
  • Texture not flagged as a virtual texture but it is large enough to be forced to be a virtual texture
  • Texture not marked as "No Mipmaps", but is on the "Color Lookup Table" LOD group, which requires "No Mipmaps"
  • Texture marked as sRGB but is on the "Color Lookup Table" LOD group, which requires "no sRGB"
  • Texture marked as sRGB but its compression settings make sRGB unsupported (e.g. Alpha, NormalMap, Masks, HDR, HalfFloat, SingleFloat)
  • When FTextureEditorToolkit::PostTextureRecode() is called
  • When texture editor is opened for the texture
  • When global Oodle settings changed

The licensee that reported the issue presented a suggested fix: dispose the preview material once preview is disabled. The change is: [Engine\Source\Editor\MaterialEditor\Private\MaterialEditor.cpp]

void FMaterialEditor::SetPreviewExpression(UMaterialExpression* NewPreviewExpression)

Old: ExpressionPreviewMaterial->GetExpressionCollection().Empty();

New: ExpressionPreviewMaterial = nullptr;

Steps to Reproduce

1. Create and edit a new material
2. Place a Texture Sample node
3. On the Details Panel for the Texture Sample node, select any texture to sample from
4. Start previewing the Texture Sample Node (e.g. "Preview" button or "Right-click – Start Previewing Node")
5. Stop previewing the Texture Sample Node (e.g. "Preview" button or "Right-click – Start Previewing Node")
6. Open the chosen texture asset for editing (e.g. through the Content Browser or the Details Panel for the Texture Sample node)

Notes:

  • Connecting or not the Texture Sample node to the Material Attributes node does not affect the crash
  • On steps 4 and 5, the previewed node can be any one that needs the result of the Texture Sample node
  • On step 6, the crash happens when trying to open any texture asset that is present in the Material Graph, regardless of whether it is actually connected and used by the previewed node or by the full material.
  • On step 6, if the texture asset was already open, the crash can also be triggered by going to it and changing one of the following properties:
  • LODGroup
  • CompressionSettings
  • CompressionQuality
  • AddressX (X-axis Tiling Method)
  • AddressY (Y-axis Tiling Method)
  • Filter
  • Srgb
  • VirtualTextureStreaming
Callstack

[Example crash trigger: opening a texture asset]

FHLSLMaterialTranslator::Texture(UTexture * InTexture, int & TextureReferenceIndex, EMaterialSamplerType SamplerType, ESamplerSourceMode SamplerSource, ETextureMipValueMode MipValueMode) Line 8778
UMaterialExpressionTextureSample::Compile(FMaterialCompiler * Compiler, int OutputIndex) Line 2806
FHLSLMaterialTranslator::CallExpression(FMaterialExpressionKey ExpressionKey, FMaterialCompiler * Compiler) Line 4823
FExpressionInput::Compile(FMaterialCompiler * Compiler) Line 368
FColorMaterialInput::CompileWithDefault(FMaterialCompiler * Compiler, EMaterialProperty Property) Line 614
UMaterial::CompilePropertyEx(FMaterialCompiler * Compiler, const FGuid & AttributeID) Line 7131
UMaterialInterface::CompileProperty(FMaterialCompiler * Compiler, EMaterialProperty Property, unsigned int ForceCastFlags) Line 4978
FMaterialResource::CompilePropertyAndSetMaterialProperty(EMaterialProperty Property, FMaterialCompiler * Compiler, EShaderFrequency OverrideShaderFrequency, bool bUsePreviousFrameTime) Line 224
FHLSLMaterialTranslator::TranslateMaterial() Line 1815
FHLSLMaterialTranslator::Translate(bool bForceDisableDDCQuery) Line 1300
FMaterial::Translate_Legacy(const FMaterialShaderMapId & ShaderMapId, const FStaticParameterSet & InStaticParameters, const ITargetPlatform * InTargetPlatform, FMaterialCompilationOutput & OutCompilationOutput, TRefCountPtr<FSharedShaderCompilerEnvironment> & OutMaterialEnvironment) Line 3352
FMaterial::Translate(const FMaterialShaderMapId & InShaderMapId, const FStaticParameterSet & InStaticParameters, const ITargetPlatform * InTargetPlatform, FMaterialCompilationOutput & OutCompilationOutput, TRefCountPtr<FSharedShaderCompilerEnvironment> & OutMaterialEnvironment) Line 3497
FMaterial::BeginCompileShaderMap(const FMaterialShaderMapId & ShaderMapId, const FStaticParameterSet & StaticParameterSet, EMaterialShaderPrecompileMode PrecompileMode, const ITargetPlatform * TargetPlatform) Line 3526
FMaterial::BeginCacheShaders::__l2::<lambda_1>::operator()() Line 3020
UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,bool __cdecl(void)>::operator()() Line 414
FMaterial::FinishCacheShaders() Line 3196
FMaterial::CacheShaders(const FMaterialShaderMapId &) Line 3212
FMaterial::CacheShaders(EMaterialShaderPrecompileMode PrecompileMode, const ITargetPlatform * TargetPlatform) Line 2775
UMaterial::CacheShadersForResources(EShaderPlatform ShaderPlatform, const TArray<FMaterialResource *,TSizedDefaultAllocator<32>> & ResourcesToCache, EMaterialShaderPrecompileMode PrecompileMode, const ITargetPlatform * TargetPlatform) Line 2839
UMaterial::CacheResourceShadersForRendering(bool bRegenerateId, EMaterialShaderPrecompileMode PrecompileMode) Line 2674
UMaterial::PostEditChangePropertyInternal(FPropertyChangedEvent & PropertyChangedEvent, const UMaterial::EPostEditChangeEffectOnShaders EffectOnShaders) Line 5368
UObject::PostEditChange() Line 514
UTexture::NotifyMaterials(const UTexture::ENotifyMaterialsEffectOnShaders EffectOnShaders) Line 4646
UTexture::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) Line 1012
FTextureEditorToolkit::PostTextureRecode() Line 160
FTextureEditorToolkit::InitTextureEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost,1> & InitToolkitHost, UObject * ObjectToEdit) Line 421
FTextureEditorModule::CreateTextureEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost,1> & InitToolkitHost, UTexture * Texture) Line 41
UAssetDefinition_Texture::OpenAssets(const FAssetOpenArgs & OpenArgs) Line 31
FAssetDefinitionProxy::OpenAssetEditor(const TArray<UObject *,TSizedDefaultAllocator<32>> & InObjects, const EAssetTypeActivationOpenedMethod OpenedMethod, TSharedPtr<IToolkitHost,1> EditWithinLevelEditor) Line 260
UAssetEditorSubsystem::OpenEditorForAsset(UObject * Asset, const EToolkitMode::Type ToolkitMode, TSharedPtr<IToolkitHost,1> OpenedFromLevelEditor, const bool bShowProgressWindow, EAssetTypeActivationOpenedMethod OpenedMethod) Line 586
SPropertyEditorAsset::OnOpenAssetEditor() Line 1658
SPropertyEditorAsset::OnAssetThumbnailDoubleClick(const FGeometry & InMyGeometry, const FPointerEvent & InMouseEvent) Line 1942
Invoke(FReply(SPropertyEditorAsset::*)(const FGeometry &, const FPointerEvent &)) Line 65
UE::Core::Private::Tuple::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(FReply(SPropertyEditorAsset::*)(const FGeometry &, const FPointerEvent &) &) Line 299
TBaseSPMethodDelegateInstance<0,SPropertyEditorAsset,1,FReply __cdecl(FGeometry const &,FPointerEvent const &),FDefaultDelegateUserPolicy>::Execute(const FGeometry & <Params_0>, const FPointerEvent & <Params_1>) Line 291
TDelegate<FReply __cdecl(FGeometry const &,FPointerEvent const &),FDefaultDelegateUserPolicy>::Execute(const FGeometry & <Params_0>, const FPointerEvent & <Params_1>) Line 613
SWidget::OnMouseButtonDoubleClick(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) Line 493
FSlateApplication::RoutePointerDoubleClickEvent::__l2::<lambda_1>::operator()(const FArrangedWidget &) Line 5958
FEventRouter::Route<FReply,FEventRouter::FBubblePolicy,FPointerEvent,`FSlateApplication::RoutePointerDoubleClickEvent'::`2'::<lambda_1>>(FSlateApplication * ThisApplication, FEventRouter::FBubblePolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::RoutePointerDoubleClickEvent::__l2::<lambda_1> & Lambda, ESlateDebuggingInputEvent DebuggingInputEvent) Line 459
FSlateApplication::RoutePointerDoubleClickEvent(const FWidgetPath & WidgetsUnderPointer, const FPointerEvent & PointerEvent) Line 5956
FSlateApplication::ProcessMouseButtonDoubleClickEvent(const TSharedPtr<FGenericWindow,1> & PlatformWindow, const FPointerEvent & InMouseEvent) Line 5941
FSlateApplication::OnMouseDoubleClick(const TSharedPtr<FGenericWindow,1> & PlatformWindow, const EMouseButtons::Type Button, const UE::Math::TVector2<double> CursorPos) Line 5904
FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage & DeferredMessage) Line 3378
FWindowsApplication::DeferMessage(TSharedPtr<FWindowsWindow,1> & NativeWindow, HWND__ * InHWnd, unsigned int InMessage, unsigned __int64 InWParam, __int64 InLParam, int MouseX, int MouseY, unsigned int RawInputFlags) Line 3903
FWindowsApplication::ProcessMessage(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 2311
WindowsApplication_WndProc(HWND__ *) Line 2128
FWindowsApplication::AppWndProc(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 2134
WinPumpMessages() Line 117
FWindowsPlatformApplicationMisc::PumpMessages(bool bFromMainLoop) Line 146
FEngineLoop::Tick() Line 5774
EngineTick() Line 60
GuardedMain(const wchar_t * CmdLine) Line 187
LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 266
WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 334

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-318809 in the post.

0
Login to Vote

Unresolved
CreatedSep 5, 2025
UpdatedSep 11, 2025
View Jira Issue