The reason is quite simple: A Unity application is not a CLI application, it is still a native code application which runs your scripts in a managed CLI environment. All callbacks that Unity provides are invoked in native C++ code. So the managed call stack starts at the entry point of the callback. An uncaught exception will go down the stack until it reaches the end. At this point Unity just displays that an exception has been caught in a callback.
An exception is by no means required to “terminate” an application. In the case of Unity an exception inside a callback just tells Unity one of the user scripts seems to be faulty. That’s not a reason to terminate the whole process. Only exceptions which results in an unpredictable state should terminate the application. Since your scripts are just a “guest” inside a Unity application managed exceptions can never terminate an application.
Keep in mind that native code exceptions (which usually also throw a managed exception) can terminate the application, however that only depends on if the exception is handled by Unity or not. At the very bottom layer you have “hard-wired” exceptions which are caught by the processor itelf and handled by the opperating system. If an exception made it’s way down there the OS usually only has the option to terminate a process since it can’t judge what this fault means to the program. Killing a program doesn’t put the OS in an undefined state, only the program itself, that’s why the OS keeps on running when a process dies.
In (nowadays) rare situations when the OS can’t handle the excetion, it might even stop the OS (which means you get a BSOD on windows).
Anyways, pure managed code or managed exceptions in Unity can’t terminate the application, just the current managed callstack.
So, I’ve found no command line switches or API to change the described behaviour. Thus I must assume there’s no way to do so (also confirmed by the @Bunny83’s answer). I was able to “abort” only by calling Debug.Break() for the editor, and Application.Quit() for regular builds, which exits an application normally. It left me with two options:
To write my own throwing routine that would log an issue and quit.
To listen to the log events and quit when an exception has been detected. As @RoflHarris and official documentation proposed.
Unfortunately, I know of no way to force my routine on other 3rd party scripts I may be using, so the option #2 looks like the only sound solution, albeit much farther down the line than I’d have liked. I ended up with this LogCallback (eventually registered in OnEnable() and unregistered in OnDisable()):
static private void OnLogException(string _message, string _stackTrace, LogType _logType)
{
if (_logType == LogType.Exception) {
if (Application.isEditor) {
// Only break in editor to allow examination of the current scene state.
Debug.Break();
}
else {
// There's no standard way to return an error code to the OS,
// so just quit regularly.
Application.Quit();
}
}
}
Thank you all for your input. It is much appreciated.
Doing something like this will allow you to catch all the logging from unity and act on what type of message has been passed through to it. This way you can get when the exception is thrown and call application.quit after logging the stack trace etc.
however I would suggest that if you have code that is likely to throw and exception use try catch blocks.
using System;
using UnityEngine;
public class CatchException : MonoBehaviour {
void OnEnable()
{
Application.RegisterLogCallback(HandleLogEntry);
}
void Update()
{
throw new System.Exception();
}
void HandleLogEntry(string logEntry, string stackTrace, LogType logType)
{
switch (logType)
{
case LogType.Exception:
Console.WriteLine("caught an exception being thrown");
break;
}
}
void OnDisable()
{
Application.RegisterLogCallback(null);
}
}
To make it abort, use Application.Quit();. However, if you look here, it says “Quits the player application. Quit is ignored in the editor or the web player.” So in editor it won’t quit still, but once you publish it, it will.
Unity keeps a log file in %localappdata%/unity something (for editor and runtime both). Why would you want your application to silently terminate, anyway? Whenever that’s happened to me I’ve only experienced irritation, never satisfaction.
There’s also Error Pause in the Console window that pauses the application when an unhandled exception is printed to the console.