diff --git a/src/3rdparty/squirrel/include/squirrel.h b/src/3rdparty/squirrel/include/squirrel.h
index 5623760fac..799c263f6b 100644
--- a/src/3rdparty/squirrel/include/squirrel.h
+++ b/src/3rdparty/squirrel/include/squirrel.h
@@ -286,6 +286,7 @@ SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc);
 SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);
 SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);
 SQUIRREL_API bool sq_resumecatch(HSQUIRRELVM v, int suspend = -1);
+SQUIRREL_API bool sq_resumeerror(HSQUIRRELVM v);
 SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror);
 SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);
 
diff --git a/src/3rdparty/squirrel/squirrel/sqapi.cpp b/src/3rdparty/squirrel/squirrel/sqapi.cpp
index 314de4dc83..4247e25236 100644
--- a/src/3rdparty/squirrel/squirrel/sqapi.cpp
+++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp
@@ -1010,6 +1010,14 @@ bool sq_resumecatch(HSQUIRRELVM v, int suspend)
 	return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_OPENTTD);
 }
 
+bool sq_resumeerror(HSQUIRRELVM v)
+{
+	SQObjectPtr ret;
+	v->_can_suspend = true;
+	v->_ops_till_suspend = 1;
+	return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_THROW_VM);
+}
+
 void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
 {
 	if(sq_gettop(v) >= 1){
diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h
index 06f2b51e9d..895c053c24 100644
--- a/src/3rdparty/squirrel/squirrel/sqclass.h
+++ b/src/3rdparty/squirrel/squirrel/sqclass.h
@@ -128,7 +128,17 @@ public:
 	}
 	void Release() {
 		_uiRef++;
-		if (_hook) { _hook(_userpointer,0);}
+		try {
+			if (_hook) { _hook(_userpointer,0);}
+		} catch (...) {
+			_uiRef--;
+			if (_uiRef == 0) {
+				SQInteger size = _memsize;
+				this->~SQInstance();
+				SQ_FREE(this, size);
+			}
+			throw;
+		}
 		_uiRef--;
 		if(_uiRef > 0) return;
 		SQInteger size = _memsize;
diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp
index 4ad1b9374d..ed9d81f42a 100644
--- a/src/3rdparty/squirrel/squirrel/sqvm.cpp
+++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp
@@ -684,10 +684,12 @@ bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQIn
 			break;
 		case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break;
 		case ET_RESUME_VM:
+		case ET_RESUME_THROW_VM:
 			traps = _suspended_traps;
 			ci->_root = _suspended_root;
 			ci->_vargs = _suspend_varargs;
 			_suspended = SQFalse;
+			if(et  == ET_RESUME_THROW_VM) { SQ_THROW(); }
 			break;
 		case ET_RESUME_OPENTTD:
 			traps = _suspended_traps;
diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h
index 18c8681e75..437fadfd57 100644
--- a/src/3rdparty/squirrel/squirrel/sqvm.h
+++ b/src/3rdparty/squirrel/squirrel/sqvm.h
@@ -53,7 +53,7 @@ struct SQVM : public CHAINABLE_OBJ
 
 typedef sqvector<CallInfo> CallInfoVec;
 public:
-	enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM, ET_RESUME_OPENTTD };
+	enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM, ET_RESUME_THROW_VM, ET_RESUME_OPENTTD };
 	SQVM(SQSharedState *ss);
 	~SQVM();
 	bool Init(SQVM *friendvm, SQInteger stacksize);
diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp
index 79f0ab5a7b..e31c8772c5 100644
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -269,7 +269,7 @@ void AIInstance::Died()
 
 void AIInstance::GameLoop()
 {
-	if (this->is_dead) return;
+	if (this->IsDead()) return;
 	if (this->engine->HasScriptCrashed()) {
 		/* The script crashed during saving, kill it here. */
 		this->Died();
@@ -322,6 +322,11 @@ void AIInstance::GameLoop()
 		} catch (AI_VMSuspend e) {
 			this->suspend  = e.GetSuspendTime();
 			this->callback = e.GetSuspendCallback();
+		} catch (AI_FatalError e) {
+			this->is_dead = true;
+			this->engine->ThrowError(e.GetErrorMessage());
+			this->engine->ResumeError();
+			this->Died();
 		}
 
 		this->is_started = true;
@@ -338,12 +343,17 @@ void AIInstance::GameLoop()
 	} catch (AI_VMSuspend e) {
 		this->suspend  = e.GetSuspendTime();
 		this->callback = e.GetSuspendCallback();
+	} catch (AI_FatalError e) {
+		this->is_dead = true;
+		this->engine->ThrowError(e.GetErrorMessage());
+		this->engine->ResumeError();
+		this->Died();
 	}
 }
 
 void AIInstance::CollectGarbage()
 {
-	if (this->is_started && !this->is_dead) this->engine->CollectGarbage();
+	if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
 }
 
 /* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
@@ -562,10 +572,25 @@ void AIInstance::Save()
 		/* We don't want to be interrupted during the save function. */
 		bool backup_allow = AIObject::GetAllowDoCommand();
 		AIObject::SetAllowDoCommand(false);
-		if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
-			/* The script crashed in the Save function. We can't kill
-			 * it here, but do so in the next AI tick. */
+		try {
+			if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
+				/* The script crashed in the Save function. We can't kill
+				 * it here, but do so in the next AI tick. */
+				SaveEmpty();
+				this->engine->CrashOccurred();
+				return;
+			}
+		} catch (AI_FatalError e) {
+			/* If we don't mark the AI as dead here cleaning up the squirrel
+			 * stack could throw AI_FatalError again. */
+			this->is_dead = true;
+			this->engine->ThrowError(e.GetErrorMessage());
+			this->engine->ResumeError();
 			SaveEmpty();
+			/* We can't kill the AI here, so mark it as crashed (not dead) and
+			 * kill it in the next AI tick. */
+			this->is_dead = false;
+			this->engine->CrashOccurred();
 			return;
 		}
 		AIObject::SetAllowDoCommand(backup_allow);
diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp
index 25d72f8a2e..f99b3c335a 100644
--- a/src/ai/ai_instance.hpp
+++ b/src/ai/ai_instance.hpp
@@ -18,7 +18,7 @@ public:
 	AI_VMSuspend(int time, AISuspendCallbackProc *callback) :
 		time(time),
 		callback(callback)
-		{}
+	{}
 
 	int GetSuspendTime() { return time; }
 	AISuspendCallbackProc *GetSuspendCallback() { return callback; }
@@ -28,6 +28,21 @@ private:
 	AISuspendCallbackProc *callback;
 };
 
+/**
+ * A throw-class that is given when the AI made a fatal error.
+ */
+class AI_FatalError {
+public:
+	AI_FatalError(const char *msg) :
+		msg(msg)
+	{}
+
+	const char *GetErrorMessage() { return msg; }
+
+private:
+	const char *msg;
+};
+
 class AIInstance {
 public:
 	friend class AIObject;
@@ -80,6 +95,11 @@ public:
 	 */
 	class AIController *GetController() { return controller; }
 
+	/**
+	 * Return the "this AI died" value
+	 */
+	inline bool IsDead() { return this->is_dead; }
+
 	/**
 	 * Call the AI Save function and save all data in the savegame.
 	 */
diff --git a/src/ai/api/ai_controller.cpp b/src/ai/api/ai_controller.cpp
index f9ef2ab166..7e7e5d0191 100644
--- a/src/ai/api/ai_controller.cpp
+++ b/src/ai/api/ai_controller.cpp
@@ -24,8 +24,7 @@
 /* static */ void AIController::Sleep(int ticks)
 {
 	if (!AIObject::GetAllowDoCommand()) {
-		AILog::Error("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.\n");
-		return;
+		throw AI_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
 	}
 
 	if (ticks <= 0) {
diff --git a/src/ai/api/ai_execmode.cpp b/src/ai/api/ai_execmode.cpp
index 941718bee1..fd3b5f62f2 100644
--- a/src/ai/api/ai_execmode.cpp
+++ b/src/ai/api/ai_execmode.cpp
@@ -4,6 +4,9 @@
 
 #include "ai_execmode.hpp"
 #include "../../command_type.h"
+#include "../../company_base.h"
+#include "../../company_func.h"
+#include "../ai_instance.hpp"
 
 bool AIExecMode::ModeProc(TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCost costs)
 {
@@ -21,6 +24,12 @@ AIExecMode::AIExecMode()
 
 AIExecMode::~AIExecMode()
 {
-	assert(this->GetDoCommandModeInstance() == this);
+	if (this->GetDoCommandModeInstance() != this) {
+		AIInstance *instance = GetCompany(_current_company)->ai_instance;
+		/* Ignore this error if the AI already died. */
+		if (!instance->IsDead()) {
+			throw AI_FatalError("AIExecMode object was removed while it was not the latest AI*Mode object created.");
+		}
+	}
 	this->SetDoCommandMode(this->last_mode, this->last_instance);
 }
diff --git a/src/ai/api/ai_object.cpp b/src/ai/api/ai_object.cpp
index 912f724157..cdf57090cb 100644
--- a/src/ai/api/ai_object.cpp
+++ b/src/ai/api/ai_object.cpp
@@ -190,8 +190,7 @@ int AIObject::GetCallbackVariable(int index)
 bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback)
 {
 	if (AIObject::GetAllowDoCommand() == false) {
-		AILog::Error("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.\n");
-		return false;
+		throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
 	}
 
 	CommandCost res;
diff --git a/src/ai/api/ai_testmode.cpp b/src/ai/api/ai_testmode.cpp
index 484333b422..c3cdb77f46 100644
--- a/src/ai/api/ai_testmode.cpp
+++ b/src/ai/api/ai_testmode.cpp
@@ -4,6 +4,9 @@
 
 #include "ai_testmode.hpp"
 #include "../../command_type.h"
+#include "../../company_base.h"
+#include "../../company_func.h"
+#include "../ai_instance.hpp"
 
 bool AITestMode::ModeProc(TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCost costs)
 {
@@ -21,6 +24,12 @@ AITestMode::AITestMode()
 
 AITestMode::~AITestMode()
 {
-	assert(this->GetDoCommandModeInstance() == this);
+	if (this->GetDoCommandModeInstance() != this) {
+		AIInstance *instance = GetCompany(_current_company)->ai_instance;
+		/* Ignore this error if the AI already died. */
+		if (!instance->IsDead()) {
+			throw AI_FatalError("AITestmode object was removed while it was not the latest AI*Mode object created.");
+		}
+	}
 	this->SetDoCommandMode(this->last_mode, this->last_instance);
 }
diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp
index 31dcf6aea0..1dd407589a 100644
--- a/src/script/squirrel.cpp
+++ b/src/script/squirrel.cpp
@@ -187,6 +187,12 @@ bool Squirrel::Resume(int suspend)
 	return this->vm->_suspended != 0;
 }
 
+void Squirrel::ResumeError()
+{
+	assert(!this->crashed);
+	sq_resumeerror(this->vm);
+}
+
 void Squirrel::CollectGarbage()
 {
 	sq_collectgarbage(this->vm);
diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp
index 612c6ce2ef..97dd7988d6 100644
--- a/src/script/squirrel.hpp
+++ b/src/script/squirrel.hpp
@@ -106,6 +106,11 @@ public:
 	 */
 	bool Resume(int suspend = -1);
 
+	/**
+	 * Resume the VM with an error so it prints a stack trace.
+	 */
+	void ResumeError();
+
 	/**
 	 * Tell the VM to do a garbage collection run.
 	 */