- Home /
Uncaught exception doesn't kill the application
For some reason, throwing an uncaught exception doesn't abort the application, i.e. all of the following code gets executed:
function Awake()
{
throw new System.Exception("Die, fiend!");
}
function Start()
{
print("Still alive");
}
Does anybody know why? And how do I make it abort?
That is a strange question. Theoretically -- no, practically -- yes. Before it's released, I will test my application in the editor many times, well, because it's convenient. Anyway, the exception doesn't kill even a regular build. Just skips the rest of the method. So it's a more expensive alias for return I guess.
Answer by Simon Says · Jul 10, 2013 at 10:11 PM
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.
I wanted to mark several answers as correct, as I have seen elsewhere on this site, but couldn't figure out how. So kudos go to the people mentioned in my answer (@Bunny83 and @RoflHarris), as they came closest to answering my question(s).
Answer by Bunny83 · Jul 10, 2013 at 01:00 AM
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.
First of all, thank you for the profound answer. Still, the analogy drawn to an OS seems strange and unfitting to me. I understand that user scripts are run in a "virtual machine" inside Unity and that any uncaught exception thrown from a script is eventually caught by Unity internally. It is how this exception is handled -- printed to a log and swallowed -- that bothers me. I think abortion or pausing the execution to allow attaching a debugger would be a much more suitable reaction.
The fact that my script encountered a fatal error (i.e. unchecked exception) and keeps running puts my application in an unpredictable state. Unity's sole purpose is to run a user's application. It doesn't manage several processes publicly, nor does it allow to start several processes in parallel, as far as I know. Hence if my application (script) is in an unpredictable state, the Unity is in an unpredictable state. An OS cannot fail under an uncaught exception from user applications, because it would compromise other, independent processes. Unity, on the other hand, compromises my application by letting it run when it clearly indicated that it hit an error it cannot cope with. An OS in its place would usually at least shut down the faulty process.
Anyway, point taken and there's nothing to it but adapt. I still don't see a good reason behind this though. Just an easier implementation for Unity developers and harder debugging for script writers.
You got the wrong view on the concept i guess. A Unity application is like an OS ;) The application runs on it's own. It is responsible for managing gameobjects and components. Your scripts are "just" behaviour scripts and from Unity's point of view each callback function it calls is like a "process". If the "process" (the function) throws an exception it can't be resumed and gets ter$$anonymous$$ated. Other components or callbacks are not affected by the exception in one of the functions.
$$anonymous$$eep in $$anonymous$$d that components should work on their own.
I understand what you're saying. It just doesn't make sense to me why would anyone want to model each callback of each $$anonymous$$onoBehaviour as a separate process, except for laziness. That's why I asked the question in the first place. GameObjects and components are interdependent -- they reference each other ins$$anonymous$$d of communicating through messages; that's a fact. It's reasonable to assume that in the real world scenarios a person would need several such objects to create a useful application and they will cooperate at some point. They are tied stronger than usual system processes. Now, even each callback of the same behaviour (which are invoked in sequence according to Unity's rules, not user's) is a virtually separate process? How good can it be? It's like assu$$anonymous$$g that Start() (i.e. more or less constructor) will have nothing to do with Update(). But it will, both callbacks will most likely access the same data. I'm trying to see a design decision behind it, yet I'm sorry, I don't see one.
Answer by tnetennba · Jul 08, 2013 at 03:00 PM
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);
}
}
Note that Application.RegisterLogCallback is now deprecated. Use Application.log$$anonymous$$essageReceived ins$$anonymous$$d, see http://docs.unity3d.com/ScriptReference/Application-log$$anonymous$$essageReceived.html.
Answer by xKroniK13x · Jul 02, 2013 at 10:24 PM
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.
Err, no, this doesn't answer my question. Thanks for the effort though. 1) Application.Quit() will never execute after an exception. It's either or. 2) Quit is not the same as abort. Abort usually returns an error code to the OS, quit returns O$$anonymous$$. I've tried under Windows.
I suppose I could implement my own ThrowException() routine, but it's equivalent to not using exceptions at all. Why are they supported, but crippled in such a way? I couldn't find it anywhere in the documentation. And this behaviour is at least non-standard.
By the way, for the editor a man could use:
if UNITY_EDITOR
if (Application.isEditor) {
EditorApplication.isPlaying = false;
}
endif
If he wanted to.
Funny thing -- the snippet works even without placing the file where it's contained in an "Editor" folder.
I haven't tried this, but System.Environment.Exit might do what you need. (I guess it would also ter$$anonymous$$ate the editor though.)
Nope, it doesn't work. Neither does System.Environment.ExitCode property. Thanks for the tip though.
When I tried this, I found out that the error code would do me no good anyway. Because when a Unity app is launched, it returns right away and runs the actual application in parallel. I figure that the only way to indicate that something went fishy to the outside world is to write it somewhere to a file or similar.
Why doesn't printing out your exceptions to the Editor console work for you? I seem to remember that all UnityExceptions are printed out to the console by default.
Answer by Loius · Jul 09, 2013 at 09:06 PM
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.
Ideally, I would want it to display a polite apology with an explanation that an unexpected error happened and suggest that the publisher should be contacted at the earliest convenience, at which point a debugger could be attached for development builds. For the lack of other options, ter$$anonymous$$ating after printing an error into the log is still better than, well, nothing.
In development builds, logs don't get checked too often unless a visible issue appears, which could be much, much later after the original problem occurred.
In release builds, an erroneous behaviour of my application could actually lead people to believe it was designed that way. Crashing ins$$anonymous$$d would be unpleasant, but it would clearly speak of an unexpected issue and would lead to a faster reporting and fixing it.
Imagine a situation when a script throws a NullPointerException in every Update() call. To a user it would look like my app is stuttering and generally slow in performance. His likely reaction would be to uninstall it and never mention it again. If it had crashed ins$$anonymous$$d, he would be more inclined to report it, if not too early in the game. It would be also more noticeable.
Ah, gotcha. I was stuck on thinking you were trying to prevent the game from surviving errors. Glad you got it working. And thanks, by the way. I'm sure I'll eventually come across the same need and now I've got at least a starting point. :)
Your answer
Follow this Question
Related Questions
Best Practices for exception handling Resource.Load 1 Answer
"Array out of range" when cycling weapons. 1 Answer
Using List.Count on Unity iPhone 2 Answers
What could be causing this problem reading from a Rect into a Vector2? 3 Answers
UnityEditor.TextEditor.DrawCursor - MIssing Method Exception -2 Answers