Quick answer: Unreal Engine stores crash logs in the Saved/Crashes directory within your project folder. Each crash creates a subdirectory containing the crash log text file, a minidump (.dmp) file, and metadata about the crash context.

This guide covers Unreal engine crash log analysis in detail. Unreal Engine provides powerful crash reporting infrastructure, but its output can be overwhelming. Between minidump files, text-based crash logs, the CrashReportClient, and the engine's assertion macros, there are multiple layers of information to parse. This guide explains how each piece fits together and how to extract the information you need to fix crashes efficiently.

Where Crash Data Lives

When an Unreal Engine game crashes, the engine writes several files to the Saved/Crashes directory. Each crash gets its own timestamped subdirectory containing a text log with the callstack, a .dmp minidump file, and an XML descriptor with metadata like the engine version, GPU driver, and operating system. For packaged builds, these files land in the platform-specific application data folder.

# Typical crash output directory structure
Saved/Crashes/
  CrashReport-2026.03.22-14.32.15/
    MyGame.log           # Full engine log up to the crash
    UEMinidump.dmp       # Windows minidump for debugger analysis
    CrashContext.runtime-xml  # Metadata about the crash
    CrashReportVideo.avi # Optional last-seconds video capture

The text log is the fastest way to get a first look at what happened. Search for Fatal error! or Assertion failed: to jump directly to the crash information.

Reading the Callstack

The crash log includes a text callstack that shows the chain of function calls leading to the crash. A typical UE callstack looks like this:

UE4Editor_MyGame!ACombatManager::ApplyDamage() [CombatManager.cpp:247]
UE4Editor_MyGame!ACombatManager::ProcessHitQueue() [CombatManager.cpp:189]
UE4Editor_Engine!UWorld::Tick() [World.cpp:1842]
UE4Editor_Engine!UGameEngine::Tick() [GameEngine.cpp:1623]
UE4Editor_Core!FEngineLoop::Tick() [LaunchEngineLoop.cpp:4847]

Each line shows the module name (before the !), the function name, and the source file with line number in brackets. Frames from your game module are the ones to focus on. The engine frames below them provide context about which system was active when the crash occurred.

Understanding Check, Ensure, and Verify Macros

Unreal Engine uses a hierarchy of assertion macros that behave differently in development and shipping builds:

check(condition) is a fatal assertion. When the condition is false, it halts execution immediately and produces a crash log with a full callstack. In shipping builds, check() is compiled out entirely, meaning the condition is never evaluated. Use it for invariants that should never be violated in correctly functioning code.

ensure(condition) is a non-fatal assertion. When the condition is false, it logs an error with a callstack but allows the game to continue running. It fires only once per call site to avoid log spam. This is ideal for catching unexpected states in production without crashing the player's game.

void ACombatManager::ApplyDamage(AActor* Target, float Damage) {
    // Fatal in dev, compiled out in shipping
    check(Target != nullptr);

    // Non-fatal, logs callstack but continues
    if (!ensure(Damage >= 0.f)) {
        Damage = 0.f;
    }

    // checkf provides a formatted message
    checkf(Target->IsValidLowLevel(),
        TEXT("ApplyDamage called with invalid target: %s"),
        *Target->GetName());
}

verify(condition) works like check() but the condition is always evaluated, even in shipping builds. Only the assertion behavior is removed. Use it when the expression has necessary side effects.

Analyzing Minidumps

The text callstack in the log file is useful for a quick overview, but the minidump contains much more information. Opening the .dmp file in Visual Studio or WinDbg lets you inspect the state of all threads, local variables, register values, and loaded modules at the moment of the crash.

To get the most out of a minidump, you need matching PDB symbol files. These are generated during compilation and must correspond to the exact build that produced the crash. Set your symbol path in Visual Studio under Debug > Options > Symbols, pointing to your symbol archive. Without symbols, you see only raw addresses and module offsets.

In WinDbg, the !analyze -v command provides an automated analysis that identifies the crashing thread, the exception type, and the probable faulting function. This is often the fastest path to understanding a crash from a minidump.

The CrashReportClient

Unreal Engine ships with CrashReportClient (CRC), a separate executable that launches when the game crashes. It collects the crash data, optionally asks the player for a description, and uploads everything to your crash reporting server. By default, CRC sends data to Epic's crash reporting infrastructure, but you can configure it to point to your own endpoint.

For indie developers, the built-in CRC setup is often more infrastructure than you need. A lighter alternative is to use an SDK like Bugnet that hooks into UE's crash handling, collects the minidump and callstack, and uploads them directly to your Bugnet dashboard. This gives you the same data without running a separate crash collection server.

"Use ensure() liberally in your gameplay code. It catches the bugs check() would catch, but without crashing your players. Save check() for true invariants in engine-level code."

Common Crash Patterns in Unreal Engine

Access violations in garbage-collected objects. Accessing a UObject after it has been garbage collected is the UE equivalent of a null pointer dereference. Always use TWeakObjectPtr or IsValid() checks for references that might outlive their target. The crash log typically shows the access violation in the frame that dereferenced the dangling pointer.

Blueprint infinite loops. A Blueprint node graph that recurses indefinitely will overflow the stack. The callstack will show a repeating pattern of the same Blueprint function. UE has a configurable recursion limit that triggers a fatal error before the OS kills the process.

Shader compilation crashes. These appear as crashes in the RHI (Rendering Hardware Interface) module, often with GPU driver functions in the callstack. They are typically driver bugs rather than game bugs. Log the GPU model and driver version from the crash metadata to identify affected hardware.

Related Issues

For a foundational guide to reading stack traces across all game engines, see reading game stack traces: a beginner's guide. If your packaged build crashes on startup, check fixing Unreal packaged build crash on startup. For collecting and symbolicating crash dumps from player machines, see capturing and symbolicating crash dumps from player devices.

Archive your PDB files on every build. The crash you cannot symbolicate is the crash you cannot ship a fix for.