Quick answer: Crash logs typically contain a stack trace showing the sequence of function calls that led to the crash, the exception type or signal that caused it, memory addresses of the faulting instruction, loaded module information, thread state at the time of the crash, and sometimes register values and memo...

This guide covers importance of crash logs in bug reports in detail. When a game crashes, the crash log is the black box. It records exactly what the program was doing at the moment of failure, which function was executing, what called that function, and what data was being processed. Without a crash log, a developer investigating a crash report has nothing to work with except the reporter’s description of what they were doing. With a crash log, they can often identify the exact line of code responsible within minutes. The difference between these two scenarios is the difference between a bug that gets fixed in an afternoon and one that stays open for months.

What Crash Logs Actually Contain

A crash log is a structured record of the program’s state at the moment it failed. The most important element is the stack trace: a list of function calls showing the execution path that led to the crash. Reading from top to bottom, the stack trace shows the function that crashed, the function that called it, the function that called that one, and so on back to the program’s entry point.

// Example stack trace from a Godot game crash
//
// ERROR: Null instance at: res://scripts/enemy_ai.gd:147
//   enemy_ai.gd:147 - in function 'update_target'
//   enemy_ai.gd:89  - in function '_physics_process'
//   combat_manager.gd:203 - in function 'process_enemies'
//   game_loop.gd:45 - in function '_process'
//
// This tells the developer:
//   - The crash was a null reference
//   - It happened in enemy_ai.gd at line 147
//   - The function was update_target()
//   - It was called during physics processing
//   - The combat_manager triggered the enemy update

Beyond the stack trace, crash logs typically include the exception type (null reference, out of bounds, segmentation fault, stack overflow), loaded modules and their versions, thread information showing which thread crashed and what other threads were doing, and sometimes register values and memory state near the faulting address. For managed languages like C# in Unity, the log also includes the exception message, which often describes the specific error in plain English.

Each of these elements helps narrow the investigation. A null reference exception points to a variable that was not initialized. An out-of-bounds error points to an array access with an invalid index. A segmentation fault in native code points to a memory corruption issue. The developer does not need to guess the category of bug; the crash log tells them.

Where to Find Crash Logs by Platform

Different engines and operating systems store crash logs in different locations. Players and testers need to know where to look.

Windows:

// Unity games:
%USERPROFILE%\AppData\LocalLow\[Company]\[Game]\Player.log

// Godot games:
%USERPROFILE%\AppData\Roaming\Godot\app_userdata\[Project]\logs\godot.log

// Unreal Engine games:
[GameDirectory]\Saved\Crashes\[CrashID]\
[GameDirectory]\Saved\Logs\[Game].log

// Windows crash dumps (any application):
%LOCALAPPDATA%\CrashDumps\

macOS:

// Unity games:
~/Library/Logs/[Company]/[Game]/Player.log

// Godot games:
~/Library/Application Support/Godot/app_userdata/[Project]/logs/

// System crash reports (any application):
~/Library/Logs/DiagnosticReports/
// Also viewable in Console.app under Crash Reports

Linux:

// Unity games:
~/.config/unity3d/[Company]/[Game]/Player.log

// Godot games:
~/.local/share/godot/app_userdata/[Project]/logs/

// System crash dumps (if coredump is enabled):
/var/lib/systemd/coredump/
// Or check: coredumpctl list

For mobile platforms, crash logs are typically accessible through platform-specific developer tools. On Android, use adb logcat to capture logs in real time. On iOS, connect the device to Xcode and check the Device Organizer for crash reports. Most mobile crash reporting SDKs upload logs to a dashboard automatically, bypassing the need for players to locate files manually.

Why “The Game Crashed” Is Not Enough

A crash report without a log is like a crime scene without evidence. The developer knows something bad happened, but they have no leads. Consider the investigation process without a crash log: the developer reads “the game crashed in the forest level,” loads the forest level, plays through it multiple times, and either reproduces the crash (lucky) or does not (much more common). If they do not reproduce it, the bug sits in the tracker indefinitely.

With a crash log, the investigation is entirely different. The developer reads the stack trace, sees that the crash occurred in enemy_ai.gd:147 when update_target tried to access a null reference, opens that file, examines line 147, and immediately sees that the code accesses a node reference that can be null if the enemy’s target is destroyed in the same frame. The fix takes ten minutes. No reproduction needed.

This is not an unusual scenario. For crashes specifically, the log provides enough information to identify the root cause without reproduction in roughly 60 to 70 percent of cases. That is an enormous efficiency gain. The remaining 30 to 40 percent still benefit from the log because it narrows the investigation area, even if it does not pinpoint the exact cause.

Automatic Crash Log Collection

Asking players to navigate to an AppData folder, find a log file, and attach it to a bug report is a significant friction point. Many players do not know how to access hidden folders. Many will not bother even if they do. The solution is to collect crash logs automatically.

Most game engines provide hooks that execute when an unhandled exception or crash occurs. In Unity, subscribe to Application.logMessageReceived to capture errors and use AppDomain.CurrentDomain.UnhandledException for fatal crashes. In Godot, the engine writes logs automatically; your reporting SDK can read and attach the most recent log file when the player opens the report form. In Unreal, the Crash Reporter module handles collection and can be configured to upload crash data to your own backend.

# Godot: Attach the most recent log file to a bug report

func get_recent_log_content() -> String:
    var log_path := OS.get_user_data_dir() + "/logs/"
    var dir := DirAccess.open(log_path)
    if dir == null:
        return ""

    # Find the most recent .log file
    var latest_file := ""
    var latest_time := 0
    dir.list_dir_begin()
    var file_name := dir.get_next()
    while file_name != "":
        if file_name.ends_with(".log"):
            var mod_time := FileAccess.get_modified_time(
                log_path + file_name)
            if mod_time > latest_time:
                latest_time = mod_time
                latest_file = file_name
        file_name = dir.get_next()

    if latest_file == "":
        return ""

    # Read the last 500 lines (most relevant for crashes)
    var content := FileAccess.get_file_as_string(
        log_path + latest_file)
    var lines := content.split("\n")
    if lines.size() > 500:
        lines = lines.slice(lines.size() - 500)
    return "\n".join(lines)

The key design decision is how much of the log to attach. Full log files can be several megabytes. For most crash investigations, the last 200 to 500 lines are sufficient, as they contain the crash itself and the events leading up to it. Truncate from the beginning, not the end, so the crash information is always present.

“Before we added automatic log collection, about 5 percent of crash reports included a log file. After making it automatic, 100 percent did. Our average time to fix crash bugs dropped from four days to six hours.”

What to Do When There Is No Crash Log

Some crashes do not produce clean log files. A hard crash — a segmentation fault in native code, a GPU driver crash, or a kernel-level failure — may terminate the process before the log can be flushed to disk. In these cases, the last few lines of the log file may be missing or the file may be truncated.

For these situations, configure your game to flush logs more frequently during development and testing builds. Most logging frameworks buffer writes for performance; reducing the buffer size or flushing after every error-level message ensures that the most important information survives a hard crash. In production builds, you can reduce flush frequency to minimize the performance impact, since most players will not encounter hard crashes.

If no log file exists at all, a minidump or core dump may be available from the operating system. On Windows, enable Windows Error Reporting to capture minidumps. On Linux, enable core dumps via ulimit -c unlimited. These files are larger and require debugging tools to read, but they contain the complete state of the crashed process, including memory contents and all thread stacks.

Related Issues

For guidance on reading and interpreting stack traces, see reading game stack traces: a beginner’s guide. To learn how to use player logs for debugging beyond crashes, read how to use player logs to debug game issues. For setting up a complete crash reporting pipeline, check how to set up crash reporting for indie games.

Add automatic log attachment to your bug reporter. Players will never find AppData on their own, and that log file is the single most valuable debugging artifact your crash reports can contain.