Quick answer: Capture both managed exceptions and burst-compiled native crashes from your Unity DOTS game, with the system, job, and world context, since the Entity Component System and the job system introduce multithreaded, data-oriented failures distinct from traditional Unity. The job-and-system context is what traces a DOTS crash to its source.
Unity DOTS, the Data-Oriented Technology Stack built around the Entity Component System, the job system, and the Burst compiler, changes how Unity games are structured and how they fail. Instead of objects with methods, you have entities, components, and systems processing data in parallel jobs, often compiled to highly-optimized native code by Burst. The crashes are different too: job-system errors, data races between parallel jobs, burst-compiled native crashes that do not look like normal C# exceptions. Setting up crash reporting for a Unity DOTS game means capturing both the managed and native crashes with the system and job context that DOTS failures require.
DOTS changes how games fail
Unity DOTS is a fundamentally different way of building games, data-oriented rather than object-oriented, with entities and components holding data and systems processing it, often in parallel jobs compiled to native code by the Burst compiler for performance. This architecture changes how the game fails: instead of exceptions in object methods, you get job-system errors, data races between parallel jobs accessing the same data, and crashes in burst-compiled native code.
These DOTS-specific failures are distinct from traditional Unity crashes. A data race, where two parallel jobs access the same data without proper synchronization, produces nondeterministic crashes that are hard to reproduce. A burst-compiled crash occurs in native code, not surfacing as a clean C# exception. The job system has its own error conditions. Understanding that DOTS introduces multithreaded, data-oriented, native-compiled failures, different from the object-oriented exceptions of traditional Unity, is the foundation for capturing DOTS crashes, which require awareness of these new failure modes.
Capture managed and native crashes
A Unity DOTS game crashes at two levels. Managed exceptions still occur in your C# systems and the non-burst parts of your code, captured through Unity exception handling as normal, with readable stack traces. But the burst-compiled jobs run as native code, and crashes there, a memory access error in a burst job, a native failure, do not surface as a clean managed exception and need native crash capture.
Capture both: hook Unity managed exception handling for the C# system crashes, and capture the native crashes that burst-compiled jobs produce, which require the native crash capture and symbolication of any native code. A burst-compiled crash is effectively a native crash, with a native backtrace that needs symbols to read, so the native crash handling that any IL2CPP or native Unity build needs applies to the burst jobs too. Covering both the managed exceptions and the burst-compiled native crashes is essential, since a DOTS game can crash at either level and missing the native level loses the burst-job crashes.
Capture the system and job context
The distinctive context for a DOTS crash is the system and job involved, since the work happens in systems processing entities via jobs, and a crash maps back to a system and a job rather than an object. Capture which system was executing and which job, where you can, so a DOTS crash is traceable to the specific system and job where it occurred, which is the DOTS equivalent of knowing the method and class.
This system-and-job context is what connects a DOTS crash to the code structure, telling you which system to investigate. Combined with the stack trace or native backtrace, it points you at the system and job that failed. For a data race, knowing the jobs involved is especially important, since the race is between specific jobs accessing the same data. Capturing the system and job context is what makes DOTS crashes traceable in the data-oriented architecture, where the relevant unit is the system and the job, not the object and method.
Watch for data races
The trickiest DOTS crash is the data race, where parallel jobs access the same data without proper synchronization, producing nondeterministic crashes or corruption that are hard to reproduce because they depend on the exact timing of the parallel execution. Unity job system has safety checks in development builds that catch many data races, but in release builds these are off, and a race that slipped through can crash in the field.
Capture the context around these intermittent, timing-dependent crashes, the jobs involved, the entities and data, since a data race is between specific jobs over specific data, and identifying them is the key to the fix, which is adding proper job dependencies or synchronization. Because data races are nondeterministic, they are reproduced by aggregating across occurrences to find the common jobs and data involved, as with any intermittent crash. Watching for data races, capturing the job and data context, and using the safety checks in development, is how you catch the multithreaded crashes that are unique to the parallel DOTS architecture.
Setting it up with Bugnet
Bugnet captures Unity DOTS crashes at both levels, hooking managed exception handling for the C# system crashes and capturing the native crashes that burst-compiled jobs produce, with symbols kept per build for symbolication of the native backtraces. You attach the system, job, and world context as custom fields, so a DOTS crash is traceable to the system and job where it occurred.
Group identical crashes into occurrence counts, which is especially valuable for the intermittent data-race crashes, since aggregating occurrences reveals the common jobs and data involved that a single nondeterministic crash does not. Because DOTS introduces multithreaded, native-compiled failures, the captured managed-and-native crashes with system-and-job context are what make them traceable, letting you find whether a crash is a managed system bug, a burst-job native crash, or a data race, and trace it to the system and jobs responsible in the data-oriented architecture.
Use the safety checks and test under load
Unity job system safety checks, active in development builds, catch many data races and job-dependency errors before they reach release, so use them, running with the safety checks on during development to catch the multithreaded bugs that would otherwise become nondeterministic release crashes. The safety checks are your first line of defense against the data races that are the hardest DOTS bugs.
Test under load, since DOTS is used for performance with many entities and parallel jobs, and the data races and job issues are more likely to manifest under the heavy parallel load DOTS is built for, where the timing windows for races are exercised. Pair the development-time safety checks and load testing with your captured crash data, which surfaces the data races and burst-job crashes that reach release despite the checks. Together they let you keep a DOTS game stable across its multithreaded, data-oriented execution, catching the parallel-execution bugs that the DOTS architecture introduces and that traditional Unity crash reporting would not anticipate.
DOTS fails in parallel jobs and native burst code. Capture both crash levels and the system and job, and watch for data races.