UText3DComponent crashes if it created from blueprint.

Hello,

We are migrating to 5.6 and encountered a crash. When the engine calls UText3DRendererBase::Create(), it crashes on line 40 because the component’s owner is nullptr. Additionally, the component itself appears to be a with a _GEN_VARIABLE prefix at the end.

quick fix for us was to add the following code to U3DComponent::OnTextRendererClassChanged:

Best regards,

Igor

`void UText3DComponent::OnTextRendererClassChanged()
{
//fix for 5.6
if (HasAnyFlags(RF_ClassDefaultObject) || !GetOwner() || GetOwner()->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
{
return;
}
//end fix
const UText3DRendererBase* RendererCDO = TextRendererClass.Get() ? TextRendererClass->GetDefaultObject() : nullptr;

if (!RendererCDO)
{
if (TextRenderer)
{
TextRendererClass = TextRenderer->GetClass();
}

return;
}`

call stack

UnrealEditor-Text3D-Win64-Debug.dll!AActor::GetActorNameOrLabel() Line 1199 C++

> UnrealEditor-Text3D-Win64-Debug.dll!UText3DRendererBase::Create() Line 40 C++

UnrealEditor-Text3D-Win64-Debug.dll!UText3DComponent::OnRegister() Line 243 C++

UnrealEditor-Engine-Win64-Debug.dll!UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext * Context) Line 2375 C++

UnrealEditor-Engine-Win64-Debug.dll!UActorComponent::RegisterComponentWithWorld(UWorld * InWorld, FRegisterComponentContext * Context) Line 1918 C++

UnrealEditor-Engine-Win64-Debug.dll!AActor::IncrementalRegisterComponents(int NumComponentsToRegister, FRegisterComponentContext * Context) Line 6181 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevel::IncrementalRegisterComponents(FRegisterComponentContext & Context) Line 2010 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevel::IncrementalUpdateComponents(int NumComponentsToUpdate, bool bRerunConstructionScripts, FRegisterComponentContext * InContext) Line 1888 C++

UnrealEditor-Engine-Win64-Debug.dll!UWorld::AddToWorld(ULevel * Level, const UE::Math::TTransform<double> & LevelTransform, bool bConsiderTimeLimit, const TOptional<UE::FTimeout const> & ExternalTimeout, FNetLevelVisibilityTransactionId TransactionId, ULevelStreaming * InOwningLevelStreaming) Line 3688 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevelStreaming::UpdateStreamingState(bool & bOutUpdateAgain, bool & bOutRedetermineTarget, const TOptional<UE::FTimeout const> & InExternalTimeout) Line 1056 C++

UnrealEditor-Engine-Win64-Debug.dll!UWorld::UpdateLevelStreaming(const TOptional<UE::FTimeout const> & ExternalTimeout) Line 4903 C++

UnrealEditor-Engine-Win64-Debug.dll!UWorld::FlushLevelStreaming(EFlushLevelStreamingType FlushType) Line 5152 C++

UnrealEditor-Engine-Win64-Debug.dll!UWorld::RefreshStreamingLevels(const TArray<ULevelStreaming *,TSizedDefaultAllocator<32>> & InLevelsToRefresh) Line 1726 C++

UnrealEditor-UnrealEd-Win64-Debug.dll!UEditorLevelUtils::AddLevelToWorld_Internal(UWorld * InWorld, const UEditorLevelUtils::FAddLevelToWorldParams & InParams) Line 486 C++

UnrealEditor-UnrealEd-Win64-Debug.dll!UEditorLevelUtils::AddLevelToWorld(UWorld * InWorld, const UEditorLevelUtils::FAddLevelToWorldParams & InParams) Line 397 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevelStreamingLevelInstanceEditor::Load(ILevelInstanceInterface * LevelInstance) Line 114 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevelInstanceSubsystem::EditLevelInstanceInternal(ILevelInstanceInterface * LevelInstance, TWeakObjectPtr<AActor,FWeakObjectPtr> ContextActorPtr, const FString & InActorNameToSelect, bool bRecursive) Line 2496 C++

UnrealEditor-Engine-Win64-Debug.dll!ULevelInstanceSubsystem::EditLevelInstance(ILevelInstanceInterface * LevelInstance, TWeakObjectPtr<AActor,FWeakObjectPtr> ContextActorPtr) Line 2410 C++

UnrealEditor-Engine-Win64-Debug.dll!ILevelInstanceInterface::EnterEdit(AActor * ContextActor) Line 311 C++

UnrealEditor-LevelInstanceEditor-Win64-Debug.dll!LevelInstanceActorDetailsCallbacks::OnEditButtonClicked(TWeakInterfacePtr<ILevelInstanceInterface> LevelInstancePtr) Line 77 C++

UnrealEditor-LevelInstanceEditor-Win64-Debug.dll!TBaseStaticDelegateInstance<FReply __cdecl(void),FDefaultDelegateUserPolicy,TWeakInterfacePtr<ILevelInstanceInterface>>::Execute() Line 791 C++

UnrealEditor-Slate-Win64-Debug.dll!SButton::ExecuteOnClick() Line 495 C++

UnrealEditor-Slate-Win64-Debug.dll!SButton::OnMouseButtonUp(const FGeometry & MyGeometry, const FPointerEvent & MouseEvent) Line 419 C++

UnrealEditor-Slate-Win64-Debug.dll!FSlateApplication::RoutePointerUpEvent::__l8::<lambda_2>::operator()(const FArrangedWidget & TargetWidget, const FPointerEvent & Event) Line 5367 C++

UnrealEditor-Slate-Win64-Debug.dll!FEventRouter::Route<FReply,FEventRouter::FToLeafmostPolicy,FPointerEvent,`FSlateApplication::RoutePointerUpEvent’::`8’::<lambda_2>>(FSlateApplication * ThisApplication, FEventRouter::FToLeafmostPolicy RoutingPolicy, FPointerEvent EventCopy, const FSlateApplication::RoutePointerUpEvent::__l8::<lambda_2> & Lambda, ESlateDebuggingInputEvent DebuggingInputEvent) Line 456 C++

UnrealEditor-Slate-Win64-Debug.dll!FSlateApplication::RoutePointerUpEvent(const FWidgetPath & WidgetsUnderPointer, const FPointerEvent & PointerEvent) Line 5353 C++

UnrealEditor-Slate-Win64-Debug.dll!FSlateApplication::ProcessMouseButtonUpEvent(const FPointerEvent & MouseEvent) Line 5938 C++

UnrealEditor-Slate-Win64-Debug.dll!FSlateApplication::OnMouseUp(const EMouseButtons::Type Button, const UE::Math::TVector2<double> CursorPos) Line 5894 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!FWindowsApplication::ProcessDeferredMessage(const FDeferredWindowsMessage & DeferredMessage) Line 3052 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!FWindowsApplication::DeferMessage(TSharedPtr<FWindowsWindow,1> & NativeWindow, HWND__ * InHWnd, unsigned int InMessage, unsigned __int64 InWParam, __int64 InLParam, int MouseX, int MouseY, unsigned int RawInputFlags) Line 3570 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!FWindowsApplication::ProcessMessage(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 1901 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!WindowsApplication_WndProc(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 1716 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!FWindowsApplication::AppWndProc(HWND__ * hwnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 1722 C++

user32.dll!UserCallWinProcCheckWow(struct _ACTIVATION_CONTEXT *,__int64 (*)(struct tagWND *,unsigned int,unsigned __int64,__int64),struct HWND__ *,enum _WM_VALUE,unsigned __int64,__int64,void *,int) Unknown

user32.dll!DispatchMessageWorker() Unknown

UnrealEditor-ApplicationCore-Win64-Debug.dll!WinPumpMessages() Line 117 C++

UnrealEditor-ApplicationCore-Win64-Debug.dll!FWindowsPlatformApplicationMisc::PumpMessages(bool bFromMainLoop) Line 148 C++

UnrealEditor-Win64-Debug.exe!FEngineLoop::Tick() Line 5554 C++

UnrealEditor-Win64-Debug.exe!EngineTick() Line 61 C++

UnrealEditor-Win64-Debug.exe!GuardedMain(const wchar_t * CmdLine) Line 190 C++

UnrealEditor-Win64-Debug.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 271 C++

UnrealEditor-Win64-Debug.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 339 C++

[Inline Frame] UnrealEditor-Win64-Debug.exe!invoke_main() Line 102 C++

UnrealEditor-Win64-Debug.exe!__scrt_common_main_seh() Line 288 C++

kernel32.dll!BaseThreadInitThunk() Unknown

ntdll.dll!RtlUserThreadStart() Unknown

Hi Igor,

I am trying to reproduce this crash here, but so far without success. From the callstack you provided, I understand the crash happens when clicking the “Level Instance -- Edit” button on the Details Panel of a Level Instance Actor, and I assume that this is linked to a level that contains an actor with a “Text 3D Component” from the “Text 3D” plugin. Is that correct? This alone does not seem to be enough to trigger the crash, however.

Would it be possible for you to provide a small repro project, or some repro steps I could follow from a blank project to trigger the crash?

Best regards,

Vitor

Hi,

This isn’t going to help a lot, but I’m running into a similar crash when trying to cook our game in 5.6

[Inlined] FString::IsEmpty() UnrealString.h.inl:337 [Inlined] AActor::GetActorNameOrLabel() Actor.h:1199 UText3DRendererBase::Create() Text3DRendererBase.cpp:40 UText3DComponent::OnRegister() Text3DComponent.cpp:240 UActorComponent::ExecuteRegisterEvents(FRegisterComponentContext *) ActorComponent.cpp:2374 UActorComponent::RegisterComponentWithWorld(UWorld *, FRegisterComponentContext *) ActorComponent.cpp:1915 AActor::IncrementalRegisterComponents(int, FRegisterComponentContext *) Actor.cpp:6180 ULevel::IncrementalRegisterComponents(FRegisterComponentContext &) Level.cpp:1987 ULevel::IncrementalUpdateComponents(int, bool, FRegisterComponentContext *) Level.cpp:1865 ULevel::UpdateLevelComponents(bool, FRegisterComponentContext *) Level.cpp:1662 UWorld::UpdateWorldComponents(bool, bool, FRegisterComponentContext *) World.cpp:2803 UEditorEngine::InitializePhysicsSceneForSaveIfNecessary(UWorld *, bool &) EditorEngine.cpp:4320 UEditorEngine::Save(UPackage *, UObject *, const wchar_t *, const FSavePackageArgs &) EditorEngine.cpp:4432 UCookOnTheFlyServer::SaveCookedPackage(UE::Cook::FSaveCookedPackageContext &) CookSavePackage.cpp:126 UCookOnTheFlyServer::PumpRuntimeSaves(UE::Cook::FTickStackData &, unsigned int, int &, bool &) CookOnTheFlyServer.cpp:5052 [Inlined] IsEngineExitRequested() CoreGlobals.h:404 UCookOnTheFlyServer::TickMainCookLoop(UE::Cook::FTickStackData &) CookOnTheFlyServer.cpp:1528 UCookOnTheFlyServer::TickCookByTheBook(const float, ECookTickFlags) CookOnTheFlyServer.cpp:1406 UCookCommandlet::RunCookByTheBookCook(UCookOnTheFlyServer *, void *, ECookByTheBookOptions) CookCommandlet.cpp:596 UCookCommandlet::CookByTheBook(const TArray<…> &) CookCommandlet.cpp:548 UCookCommandlet::Main(const FString &) CookCommandlet.cpp:266 FEngineLoop::PreInitPostStartupScreen(const wchar_t *) LaunchEngineLoop.cpp:3886 [Inlined] FEngineLoop::PreInit(const wchar_t *) LaunchEngineLoop.cpp:4185 [Inlined] EnginePreInit(const wchar_t *) Launch.cpp:40 GuardedMain(const wchar_t *) Launch.cpp:143 LaunchWindowsStartup(HINSTANCE__ *, HINSTANCE__ *, char *, int, const wchar_t *) LaunchWindows.cpp:271 WinMain(HINSTANCE__ *, HINSTANCE__ *, char *, int) LaunchWindows.cpp:339 [Inlined] invoke_main() 0x00007ff77697b4ae __scrt_common_main_seh() 0x00007ff77697b48d <unknown> 0x00007ffc3363259d <unknown> 0x00007ffc34c4af78with

  • in UText3DRendererBase::Create
    • Text3DComponent pointing to Text3D_GEN_VARIABLE
    • its owner being nullptr
  • in UText3DComponent::OnRegister
    • this pointing to an actual Text3D component of a StaticMeshActor

So it seems that an actor has a Text3DComponent which uses a TextRenderer whose outer is not the component itself, but instead a _GEN_VARIABLE. I’m still trying to figure out what’s going on exactly

Hi Igor and Nicolas,

I was able to repro the crash by following these quick steps:

- Enable plugin “Text 3D”

- Create a new Bluprint Class based on C++ Class “Text3DActor”

- Save the new asset

- Right-click the new asset -- asset Actions -- Reload (or close and reopen the Editor)

- Double-click the new asset to edit the Blueprint (CRASH)

I also did some investigation on the root cause of the problem. Each instance of UText3DComponent expects to have its own “TextRenderer” internal object, which should always have the component as its outer. However, in several situations, the Engine creates new objects in default state by copying their data from their class CDO or from blueprint-generated “_GEN_VARIABLE” objects. In these situations, the “TextRenderer” object is being fully copied, including its Outer, and not being fixed-up later as it should (this would be desired if the TextRenderer was an external object possibly referenced by multiple Text3DComponents, for example, but this is not the case here). The result is that the component ends up with a TextRenderer that references the wrong Outer.

If you are building the engine from source, you might be able to solve this by simply adding the “Instanced” tag to the UPROPERTY() macro of UText3DComponent’s TextRenderer property. If not building from source, you can try to copy the code from UText3DComponent into a new component of your own and apply the fix there. In case this is impossible because of some non-exported C++ symbol, you can try copying the entire Text3D plugin into a new one instead.

I noticed that this crash has already been fixed in the latest version of the source code from the repo. The “Instanced” tag was added by CL 43614780 in ue5-main branch in Perforce, and by commmit 0140842c1640c2a5ad8302fa159484f6859c5df0 on GitHub. I’m not sure, however, if this can be applied on its own, since it is part of a larger (still ongoing) work on UText3DComponent.

I hope this is helpful. Please let me know if you need further assistance.

Best regards,

Vitor

Hi Vitor

I’m not sure when I can try to provide an empty project (we’re still in the process of stabilizing the project after migration). But additional information I missed in my first post is that UText3DComponent must be part of the blueprint class. Your idea with “I assume that this is linked to a level that contains an actor with a “Text 3D Component” from the “Text 3D” plugin.” is totally correct.

Regards Igor.

Hi Vitor, thanks for getting back to us. Unfortunately, as you expected, the CL can’t be applied directly onto the 5.6.0 release. I tried adding the Instanced tag to the TextRenderer’s UPROPERTY macro, but that results in the following fatal error:

[2025.07.22-12.54.03:131][ 0]LogWindows: Error: appError called: Fatal error: [File:D:\DNE\git\monorepo\5.6\UE\Engine\Source\Runtime\CoreUObject\Private\UObject\SavePackage2.cpp] [Line: 1572] Text3DStaticMeshesRenderer /Gym/Blueprint/BP_Gym_3DTextLevel.Default__BP_Gym_3DTextLevel_C:Text3DComponent.StaticMeshesRenderer was an archetype of Text3DStaticMeshesRenderer /Gym/Map/LVL_TPL_Gym/LVL_TPL_Gym_CommonLevelInstance.LVL_TPL_Gym_CommonLevelInstance:PersistentLevel.BP_Gym_3DTextLevel_C_0.Text3DComponent.StaticMeshesRenderer but returned a null index mapping the object.

Hmmm… Maybe also add “DefaultToInstanced” to the TextRenderer UCLASS, or dropping the “Transient” from the UPROPERTY. I’ll also test these and other changes here and get back to you.

Hmm, the current release doesn’t have Transient on the UPROPERTY. I’ll try adding DefaultToInstanced though, thanks

edit: it didn’t fix the issue either :frowning:

Hi Igor and Nicolas,

Sorry, when I mentioned dropping “Transient”, what I actually wanted to say was to replace RF_Transient with RF_Public on [Text3DComponent.cpp:997], when the TextRenderer is created by calling NewObject<UText3DRendererBase>().

If you still get that error after adding “Instanced” to the UPROPERTY and making the change above, can you provide more context on it? Do you get it when trying to cook the project?

Also, one thing I tried that did seem to work in my simple test project was to download the Text3D plugin source code from UE 5.5.4 (zip-file attached to this post) and add it as a project plugin. It should override the built-in plugin from UE 5.6 and hopefully work without any other changes to existing projects. Its only dependency seems to be the “Motion Design” (A.K.A. “Avalanche”) plugin from the Virtual Production category, so make sure you don’t need it. Kind of a dirty workaround, but might be a good “last resort”.

Hope that helps!

Thanks for clarifying, replacing RF_Transient with RF_Public seems to have fixed the issue (or at least I was able to cook without any errors about Text3D). I still need to run some more tests on packages, but it’s looking good :slight_smile: