diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp
index 5892b4a30..72c4fd0e9 100644
--- a/src/libslic3r/AppConfig.cpp
+++ b/src/libslic3r/AppConfig.cpp
@@ -1,6 +1,7 @@
 #include "libslic3r/libslic3r.h"
 #include "libslic3r/Utils.hpp"
 #include "AppConfig.hpp"
+#include "Exception.hpp"
 
 #include <utility>
 #include <vector>
@@ -126,7 +127,7 @@ std::string AppConfig::load()
         // ! But to avoid the use of _utf8 (related to use of wxWidgets) 
         // we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
         /*
-        throw std::runtime_error(
+        throw Slic3r::RuntimeError(
         	_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
                     "Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) + 
         	"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp
index 08f01d8d8..71746f32e 100644
--- a/src/libslic3r/BoundingBox.hpp
+++ b/src/libslic3r/BoundingBox.hpp
@@ -2,6 +2,7 @@
 #define slic3r_BoundingBox_hpp_
 
 #include "libslic3r.h"
+#include "Exception.hpp"
 #include "Point.hpp"
 #include "Polygon.hpp"
 
@@ -22,7 +23,7 @@ public:
     {
         if (points.empty()) {
             this->defined = false;
-            // throw std::invalid_argument("Empty point set supplied to BoundingBoxBase constructor");
+            // throw Slic3r::InvalidArgument("Empty point set supplied to BoundingBoxBase constructor");
         } else {
             typename std::vector<PointClass>::const_iterator it = points.begin();
             this->min = *it;
@@ -68,7 +69,7 @@ public:
     BoundingBox3Base(const std::vector<PointClass>& points)
     {
         if (points.empty())
-            throw std::invalid_argument("Empty point set supplied to BoundingBox3Base constructor");
+            throw Slic3r::InvalidArgument("Empty point set supplied to BoundingBox3Base constructor");
         typename std::vector<PointClass>::const_iterator it = points.begin();
         this->min = *it;
         this->max = *it;
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index f3f365b47..25ef93430 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -5,7 +5,6 @@
 #include <fstream>
 #include <iostream>
 #include <iomanip>
-#include <exception> // std::runtime_error
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/erase.hpp>
@@ -218,7 +217,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
 	    case coInts:            return new ConfigOptionIntsNullable();
 	    case coPercents:        return new ConfigOptionPercentsNullable();
 	    case coBools:           return new ConfigOptionBoolsNullable();
-	    default:                throw std::runtime_error(std::string("Unknown option type for nullable option ") + this->label);
+	    default:                throw Slic3r::RuntimeError(std::string("Unknown option type for nullable option ") + this->label);
 	    }
 	} else {
 	    switch (this->type) {
@@ -238,7 +237,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
 	    case coBool:            return new ConfigOptionBool();
 	    case coBools:           return new ConfigOptionBools();
 	    case coEnum:            return new ConfigOptionEnumGeneric(this->enum_keys_map);
-	    default:                throw std::runtime_error(std::string("Unknown option type for option ") + this->label);
+	    default:                throw Slic3r::RuntimeError(std::string("Unknown option type for option ") + this->label);
 	    }
 	}
 }
@@ -535,7 +534,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
         return opt_def->ratio_over.empty() ? 0. : 
             static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over));
     }
-    throw std::runtime_error("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
+    throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
 }
 
 // Return an absolute value of a possibly relative config variable.
@@ -546,7 +545,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double rati
     const ConfigOption *raw_opt = this->option(opt_key);
     assert(raw_opt != nullptr);
     if (raw_opt->type() != coFloatOrPercent)
-        throw std::runtime_error("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
+        throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
     // Compute absolute value.
     return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(ratio_over);
 }
@@ -609,7 +608,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file)
 		std::getline(ifs, firstline);
 		if (strncmp(slic3r_gcode_header, firstline.c_str(), strlen(slic3r_gcode_header)) != 0 &&
             strncmp(prusaslicer_gcode_header, firstline.c_str(), strlen(prusaslicer_gcode_header)) != 0)
-			throw std::runtime_error("Not a PrusaSlicer / Slic3r PE generated g-code.");
+			throw Slic3r::RuntimeError("Not a PrusaSlicer / Slic3r PE generated g-code.");
 	}
     ifs.seekg(0, ifs.end);
 	auto file_length = ifs.tellg();
@@ -621,7 +620,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file)
 
     size_t key_value_pairs = load_from_gcode_string(data.data());
     if (key_value_pairs < 80)
-        throw std::runtime_error(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
+        throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
 }
 
 // Load the config keys from the given string.
@@ -750,7 +749,7 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
         throw NoDefinitionException(opt_key);
     const ConfigOptionDef *optdef = def->get(opt_key);
     if (optdef == nullptr)
-//        throw std::runtime_error(std::string("Invalid option name: ") + opt_key);
+//        throw Slic3r::RuntimeError(std::string("Invalid option name: ") + opt_key);
         // Let the parent decide what to do if the opt_key is not defined by this->def().
         return nullptr;
     ConfigOption *opt = optdef->create_default_option();
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 87e020898..28b28b405 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -13,6 +13,7 @@
 #include <vector>
 #include "libslic3r.h"
 #include "clonable_ptr.hpp"
+#include "Exception.hpp"
 #include "Point.hpp"
 
 #include <boost/algorithm/string/trim.hpp>
@@ -34,31 +35,31 @@ extern bool         unescape_string_cstyle(const std::string &str, std::string &
 extern bool         unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
 
 /// Specialization of std::exception to indicate that an unknown config option has been encountered.
-class UnknownOptionException : public std::runtime_error {
+class UnknownOptionException : public Slic3r::RuntimeError {
 public:
     UnknownOptionException() :
-        std::runtime_error("Unknown option exception") {}
+        Slic3r::RuntimeError("Unknown option exception") {}
     UnknownOptionException(const std::string &opt_key) :
-        std::runtime_error(std::string("Unknown option exception: ") + opt_key) {}
+        Slic3r::RuntimeError(std::string("Unknown option exception: ") + opt_key) {}
 };
 
 /// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
-class NoDefinitionException : public std::runtime_error
+class NoDefinitionException : public Slic3r::RuntimeError
 {
 public:
     NoDefinitionException() :
-        std::runtime_error("No definition exception") {}
+        Slic3r::RuntimeError("No definition exception") {}
     NoDefinitionException(const std::string &opt_key) :
-        std::runtime_error(std::string("No definition exception: ") + opt_key) {}
+        Slic3r::RuntimeError(std::string("No definition exception: ") + opt_key) {}
 };
 
 /// Indicate that an unsupported accessor was called on a config option.
-class BadOptionTypeException : public std::runtime_error
+class BadOptionTypeException : public Slic3r::RuntimeError
 {
 public:
-	BadOptionTypeException() : std::runtime_error("Bad option type exception") {}
-	BadOptionTypeException(const std::string &message) : std::runtime_error(message) {}
-    BadOptionTypeException(const char* message) : std::runtime_error(message) {}
+	BadOptionTypeException() : Slic3r::RuntimeError("Bad option type exception") {}
+	BadOptionTypeException(const std::string &message) : Slic3r::RuntimeError(message) {}
+    BadOptionTypeException(const char* message) : Slic3r::RuntimeError(message) {}
 };
 
 // Type of a configuration value.
@@ -167,7 +168,7 @@ public:
     void set(const ConfigOption *rhs) override
     {
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionSingle: Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionSingle: Assigning an incompatible type");
         assert(dynamic_cast<const ConfigOptionSingle<T>*>(rhs));
         this->value = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
     }
@@ -175,7 +176,7 @@ public:
     bool operator==(const ConfigOption &rhs) const override
     {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionSingle: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionSingle: Comparing incompatible types");
         assert(dynamic_cast<const ConfigOptionSingle<T>*>(&rhs));
         return this->value == static_cast<const ConfigOptionSingle<T>*>(&rhs)->value;
     }
@@ -239,7 +240,7 @@ public:
     void set(const ConfigOption *rhs) override
     {
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionVector: Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionVector: Assigning an incompatible type");
         assert(dynamic_cast<const ConfigOptionVector<T>*>(rhs));
         this->values = static_cast<const ConfigOptionVector<T>*>(rhs)->values;
     }
@@ -256,12 +257,12 @@ public:
             if (opt->type() == this->type()) {
                 auto other = static_cast<const ConfigOptionVector<T>*>(opt);
                 if (other->values.empty())
-                    throw std::runtime_error("ConfigOptionVector::set(): Assigning from an empty vector");
+                    throw Slic3r::RuntimeError("ConfigOptionVector::set(): Assigning from an empty vector");
                 this->values.emplace_back(other->values.front());
             } else if (opt->type() == this->scalar_type())
                 this->values.emplace_back(static_cast<const ConfigOptionSingle<T>*>(opt)->value);
             else
-                throw std::runtime_error("ConfigOptionVector::set():: Assigning an incompatible type");
+                throw Slic3r::RuntimeError("ConfigOptionVector::set():: Assigning an incompatible type");
         }
     }
 
@@ -280,12 +281,12 @@ public:
             // Assign the first value of the rhs vector.
             auto other = static_cast<const ConfigOptionVector<T>*>(rhs);
             if (other->values.empty())
-                throw std::runtime_error("ConfigOptionVector::set_at(): Assigning from an empty vector");
+                throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning from an empty vector");
             this->values[i] = other->get_at(j);
         } else if (rhs->type() == this->scalar_type())
             this->values[i] = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
         else
-            throw std::runtime_error("ConfigOptionVector::set_at(): Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning an incompatible type");
     }
 
     const T& get_at(size_t i) const
@@ -310,9 +311,9 @@ public:
         else if (n > this->values.size()) {
             if (this->values.empty()) {
                 if (opt_default == nullptr)
-                    throw std::runtime_error("ConfigOptionVector::resize(): No default value provided.");
+                    throw Slic3r::RuntimeError("ConfigOptionVector::resize(): No default value provided.");
                 if (opt_default->type() != this->type())
-                    throw std::runtime_error("ConfigOptionVector::resize(): Extending with an incompatible type.");
+                    throw Slic3r::RuntimeError("ConfigOptionVector::resize(): Extending with an incompatible type.");
                 this->values.resize(n, static_cast<const ConfigOptionVector<T>*>(opt_default)->values.front());
             } else {
                 // Resize by duplicating the last value.
@@ -329,7 +330,7 @@ public:
     bool operator==(const ConfigOption &rhs) const override
     {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionVector: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionVector: Comparing incompatible types");
         assert(dynamic_cast<const ConfigOptionVector<T>*>(&rhs));
         return this->values == static_cast<const ConfigOptionVector<T>*>(&rhs)->values;
     }
@@ -341,9 +342,9 @@ public:
     // An option overrides another option if it is not nil and not equal.
     bool overriden_by(const ConfigOption *rhs) const override {
         if (this->nullable())
-        	throw std::runtime_error("Cannot override a nullable ConfigOption.");
+        	throw Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionVector.overriden_by() applied to different types.");
+            throw Slic3r::RuntimeError("ConfigOptionVector.overriden_by() applied to different types.");
     	auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
     	if (! rhs->nullable())
     		// Overridding a non-nullable object with another non-nullable object.
@@ -361,9 +362,9 @@ public:
     // Apply an override option, possibly a nullable one.
     bool apply_override(const ConfigOption *rhs) override {
         if (this->nullable())
-        	throw std::runtime_error("Cannot override a nullable ConfigOption.");
+        	throw Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
         if (rhs->type() != this->type())
-			throw std::runtime_error("ConfigOptionVector.apply_override() applied to different types.");
+			throw Slic3r::RuntimeError("ConfigOptionVector.apply_override() applied to different types.");
 		auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
 		if (! rhs->nullable()) {
     		// Overridding a non-nullable object with another non-nullable object.
@@ -452,7 +453,7 @@ public:
     bool                    operator==(const ConfigOptionFloatsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
     bool 					operator==(const ConfigOption &rhs) const override {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionFloatsTempl: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionFloatsTempl: Comparing incompatible types");
         assert(dynamic_cast<const ConfigOptionVector<double>*>(&rhs));
         return vectors_equal(this->values, static_cast<const ConfigOptionVector<double>*>(&rhs)->values);
     }
@@ -499,7 +500,7 @@ public:
         		if (NULLABLE)
         			this->values.push_back(nil_value());
         		else
-        			throw std::runtime_error("Deserializing nil into a non-nullable object");
+        			throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
         	} else {
 	            std::istringstream iss(item_str);
 	            double value;
@@ -524,9 +525,9 @@ protected:
         		if (NULLABLE)
         			ss << "nil";
         		else
-                    throw std::runtime_error("Serializing NaN");
+                    throw Slic3r::RuntimeError("Serializing NaN");
         	} else
-                throw std::runtime_error("Serializing invalid number");
+                throw Slic3r::RuntimeError("Serializing invalid number");
 	}
     static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
     	if (NULLABLE) {
@@ -645,7 +646,7 @@ public:
         		if (NULLABLE)
         			this->values.push_back(nil_value());
         		else
-                    throw std::runtime_error("Deserializing nil into a non-nullable object");
+                    throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
         	} else {
 	            std::istringstream iss(item_str);
 	            int value;
@@ -662,7 +663,7 @@ private:
         		if (NULLABLE)
         			ss << "nil";
         		else
-                    throw std::runtime_error("Serializing NaN");
+                    throw Slic3r::RuntimeError("Serializing NaN");
         	} else
         		ss << v;
 	}
@@ -847,7 +848,7 @@ public:
     bool                        operator==(const ConfigOption &rhs) const override
     {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionFloatOrPercent: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Comparing incompatible types");
         assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(&rhs));
         return *this == *static_cast<const ConfigOptionFloatOrPercent*>(&rhs);
     }
@@ -858,7 +859,7 @@ public:
 
     void set(const ConfigOption *rhs) override {
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionFloatOrPercent: Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
         assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(rhs));
         *this = *static_cast<const ConfigOptionFloatOrPercent*>(rhs);
     }
@@ -1126,7 +1127,7 @@ public:
         		if (NULLABLE)
         			this->values.push_back(nil_value());
         		else
-                    throw std::runtime_error("Deserializing nil into a non-nullable object");
+                    throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
         	} else
         		this->values.push_back(item_str.compare("1") == 0);	
         }
@@ -1139,7 +1140,7 @@ protected:
         		if (NULLABLE)
         			ss << "nil";
         		else
-                    throw std::runtime_error("Serializing NaN");
+                    throw Slic3r::RuntimeError("Serializing NaN");
         	} else
         		ss << (v ? "1" : "0");
 	}
@@ -1175,14 +1176,14 @@ public:
     bool operator==(const ConfigOption &rhs) const override
     {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionEnum<T>: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionEnum<T>: Comparing incompatible types");
         // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
         return this->value == (T)rhs.getInt();
     }
 
     void set(const ConfigOption *rhs) override {
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionEnum<T>: Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionEnum<T>: Assigning an incompatible type");
         // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
         this->value = (T)rhs->getInt();
     }
@@ -1259,14 +1260,14 @@ public:
     bool operator==(const ConfigOption &rhs) const override
     {
         if (rhs.type() != this->type())
-            throw std::runtime_error("ConfigOptionEnumGeneric: Comparing incompatible types");
+            throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Comparing incompatible types");
         // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
         return this->value == rhs.getInt();
     }
 
     void set(const ConfigOption *rhs) override {
         if (rhs->type() != this->type())
-            throw std::runtime_error("ConfigOptionEnumGeneric: Assigning an incompatible type");
+            throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Assigning an incompatible type");
         // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
         this->value = rhs->getInt();
     }
@@ -1321,7 +1322,7 @@ public:
 		    case coInts:            { auto opt = new ConfigOptionIntsNullable();	archive(*opt); return opt; }
 		    case coPercents:        { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
 		    case coBools:           { auto opt = new ConfigOptionBoolsNullable();	archive(*opt); return opt; }
-		    default:                throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
+		    default:                throw Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
 		    }
     	} else {
 		    switch (this->type) {
@@ -1340,7 +1341,7 @@ public:
 		    case coBool:            { auto opt = new ConfigOptionBool(); 			archive(*opt); return opt; }
 		    case coBools:           { auto opt = new ConfigOptionBools(); 			archive(*opt); return opt; }
 		    case coEnum:            { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
-		    default:                throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
+		    default:                throw Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
 		    }
 		}
 	}
@@ -1352,7 +1353,7 @@ public:
 		    case coInts:            archive(*static_cast<const ConfigOptionIntsNullable*>(opt));    break;
 		    case coPercents:        archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
 		    case coBools:           archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); 	break;
-		    default:                throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
+		    default:                throw Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
 		    }
 		} else {
 		    switch (this->type) {
@@ -1371,7 +1372,7 @@ public:
 		    case coBool:            archive(*static_cast<const ConfigOptionBool*>(opt)); 			break;
 		    case coBools:           archive(*static_cast<const ConfigOptionBools*>(opt)); 			break;
 		    case coEnum:            archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); 	break;
-		    default:                throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
+		    default:                throw Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
 		    }
 		}
 		// Make the compiler happy, shut up the warnings.
diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp
index daaab4755..5bdd5055e 100644
--- a/src/libslic3r/ExPolygon.cpp
+++ b/src/libslic3r/ExPolygon.cpp
@@ -1,5 +1,6 @@
 #include "BoundingBox.hpp"
 #include "ExPolygon.hpp"
+#include "Exception.hpp"
 #include "Geometry.hpp"
 #include "Polygon.hpp"
 #include "Line.hpp"
@@ -435,7 +436,7 @@ void ExPolygon::triangulate_pp(Polygons* polygons) const
     std::list<TPPLPoly> output;
     int res = TPPLPartition().Triangulate_MONO(&input, &output);
     if (res != 1)
-        throw std::runtime_error("Triangulation failed");
+        throw Slic3r::RuntimeError("Triangulation failed");
     
     // convert output polygons
     for (std::list<TPPLPoly>::iterator poly = output.begin(); poly != output.end(); ++poly) {
@@ -548,7 +549,7 @@ void ExPolygon::triangulate_pp(Points *triangles) const
     int res = TPPLPartition().Triangulate_MONO(&input, &output);
 // int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) {
     if (res != 1)
-        throw std::runtime_error("Triangulation failed");
+        throw Slic3r::RuntimeError("Triangulation failed");
     *triangles = polypartition_output_to_triangles(output);
 }
 
@@ -591,7 +592,7 @@ void ExPolygon::triangulate_p2t(Polygons* polygons) const
                 }
                 polygons->push_back(p);
             }
-        } catch (const std::runtime_error & /* err */) {
+        } catch (const Slic3r::RuntimeError & /* err */) {
             assert(false);
             // just ignore, don't triangulate
         }
diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp
new file mode 100644
index 000000000..8ec9f20c8
--- /dev/null
+++ b/src/libslic3r/Exception.hpp
@@ -0,0 +1,28 @@
+#ifndef _libslic3r_Exception_h_
+#define _libslic3r_Exception_h_
+
+#include <stdexcept>
+
+namespace Slic3r {
+
+// PrusaSlicer's own exception hierarchy is derived from std::runtime_error.
+// Base for Slicer's own exceptions.
+class Exception : public std::runtime_error { using std::runtime_error::runtime_error; };
+#define SLIC3R_DERIVE_EXCEPTION(DERIVED_EXCEPTION, PARENT_EXCEPTION) \
+    class DERIVED_EXCEPTION : public PARENT_EXCEPTION { using PARENT_EXCEPTION::PARENT_EXCEPTION; }
+// Critical exception produced by Slicer, such exception shall never propagate up to the UI thread.
+// If that happens, an ugly fat message box with an ugly fat exclamation mark is displayed.
+SLIC3R_DERIVE_EXCEPTION(CriticalException,  Exception);
+SLIC3R_DERIVE_EXCEPTION(RuntimeError,       CriticalException);
+SLIC3R_DERIVE_EXCEPTION(LogicError,         CriticalException);
+SLIC3R_DERIVE_EXCEPTION(InvalidArgument,    LogicError);
+SLIC3R_DERIVE_EXCEPTION(OutOfRange,         LogicError);
+SLIC3R_DERIVE_EXCEPTION(IOError,            CriticalException);
+SLIC3R_DERIVE_EXCEPTION(FileIOError,        IOError);
+// Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications.
+SLIC3R_DERIVE_EXCEPTION(SlicingError,       Exception);
+#undef SLIC3R_DERIVE_EXCEPTION
+
+} // namespace Slic3r
+
+#endif // _libslic3r_Exception_h_
diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp
index dfece6949..5e40ab32e 100644
--- a/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -2,6 +2,7 @@
 #define slic3r_ExtrusionEntityCollection_hpp_
 
 #include "libslic3r.h"
+#include "Exception.hpp"
 #include "ExtrusionEntity.hpp"
 
 namespace Slic3r {
@@ -107,7 +108,7 @@ public:
 
     // Following methods shall never be called on an ExtrusionEntityCollection.
     Polyline as_polyline() const override {
-        throw std::runtime_error("Calling as_polyline() on a ExtrusionEntityCollection");
+        throw Slic3r::RuntimeError("Calling as_polyline() on a ExtrusionEntityCollection");
         return Polyline();
     };
 
@@ -117,7 +118,7 @@ public:
     }
 
     double length() const override {
-        throw std::runtime_error("Calling length() on a ExtrusionEntityCollection");
+        throw Slic3r::RuntimeError("Calling length() on a ExtrusionEntityCollection");
         return 0.;        
     }
 };
diff --git a/src/libslic3r/FileParserError.hpp b/src/libslic3r/FileParserError.hpp
index 3f560fa4f..b7e63d84e 100644
--- a/src/libslic3r/FileParserError.hpp
+++ b/src/libslic3r/FileParserError.hpp
@@ -10,14 +10,14 @@
 namespace Slic3r {
 
 // Generic file parser error, mostly copied from boost::property_tree::file_parser_error
-class file_parser_error: public std::runtime_error
+class file_parser_error: public Slic3r::RuntimeError
 {
 public:
     file_parser_error(const std::string &msg, const std::string &file, unsigned long line = 0) :
-        std::runtime_error(format_what(msg, file, line)),
+        Slic3r::RuntimeError(format_what(msg, file, line)),
         m_message(msg), m_filename(file), m_line(line) {}
     file_parser_error(const std::string &msg, const boost::filesystem::path &file, unsigned long line = 0) :
-        std::runtime_error(format_what(msg, file.string(), line)),
+        Slic3r::RuntimeError(format_what(msg, file.string(), line)),
         m_message(msg), m_filename(file.string()), m_line(line) {}
     // gcc 3.4.2 complains about lack of throw specifier on compiler
     // generated dtor
@@ -35,7 +35,7 @@ private:
     std::string     m_filename;
     unsigned long   m_line;
 
-    // Format error message to be returned by std::runtime_error::what()
+    // Format error message to be returned by Slic3r::RuntimeError::what()
     static std::string format_what(const std::string &msg, const std::string &file, unsigned long l)
     {
         std::stringstream stream;
diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp
index 9001330aa..b0319efde 100644
--- a/src/libslic3r/Fill/FillBase.cpp
+++ b/src/libslic3r/Fill/FillBase.cpp
@@ -2,6 +2,7 @@
 
 #include "../ClipperUtils.hpp"
 #include "../EdgeGrid.hpp"
+#include "../Exception.hpp"
 #include "../Geometry.hpp"
 #include "../Surface.hpp"
 #include "../PrintConfig.hpp"
@@ -40,7 +41,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
     case ipOctagramSpiral:      return new FillOctagramSpiral();
     case ipAdaptiveCubic:       return new FillAdaptive();
     case ipSupportCubic:        return new FillSupportCubic();
-    default: throw std::invalid_argument("unknown type");
+    default: throw Slic3r::InvalidArgument("unknown type");
     }
 }
 
diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp
index dd887b8c3..77620e118 100644
--- a/src/libslic3r/Fill/FillBase.hpp
+++ b/src/libslic3r/Fill/FillBase.hpp
@@ -11,6 +11,7 @@
 
 #include "../libslic3r.h"
 #include "../BoundingBox.hpp"
+#include "../Exception.hpp"
 #include "../Utils.hpp"
 
 namespace Slic3r {
@@ -23,9 +24,10 @@ namespace FillAdaptive_Internal {
     struct Octree;
 };
 
-class InfillFailedException : public std::runtime_error {
+// Infill shall never fail, therefore the error is classified as RuntimeError, not SlicingError.
+class InfillFailedException : public Slic3r::RuntimeError {
 public:
-    InfillFailedException() : std::runtime_error("Infill failed") {}
+    InfillFailedException() : Slic3r::RuntimeError("Infill failed") {}
 };
 
 struct FillParams
diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp
index 1678be999..e5dcf0731 100644
--- a/src/libslic3r/Flow.cpp
+++ b/src/libslic3r/Flow.cpp
@@ -53,7 +53,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
 	else if (opt_key == "support_material_extrusion_width")
     	return frSupportMaterial;
     else 
-    	throw std::runtime_error("opt_key_to_flow_role: invalid argument");
+    	throw Slic3r::RuntimeError("opt_key_to_flow_role: invalid argument");
 };
 
 static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key) 
@@ -126,7 +126,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
 {
     // we need layer height unless it's a bridge
     if (height <= 0 && bridge_flow_ratio == 0) 
-        throw std::invalid_argument("Invalid flow height supplied to new_from_config_width()");
+        throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_config_width()");
 
     float w;
     if (bridge_flow_ratio > 0) {
@@ -151,7 +151,7 @@ Flow Flow::new_from_spacing(float spacing, float nozzle_diameter, float height,
 {
     // we need layer height unless it's a bridge
     if (height <= 0 && !bridge) 
-        throw std::invalid_argument("Invalid flow height supplied to new_from_spacing()");
+        throw Slic3r::InvalidArgument("Invalid flow height supplied to new_from_spacing()");
     // Calculate width from spacing.
     // For normal extrusons, extrusion width is wider than the spacing due to the rounding and squishing of the extrusions.
     // For bridge extrusions, the extrusions are placed with a tiny BRIDGE_EXTRA_SPACING gaps between the threads.
diff --git a/src/libslic3r/Flow.hpp b/src/libslic3r/Flow.hpp
index 7d6e35873..9e57ce907 100644
--- a/src/libslic3r/Flow.hpp
+++ b/src/libslic3r/Flow.hpp
@@ -3,6 +3,7 @@
 
 #include "libslic3r.h"
 #include "Config.hpp"
+#include "Exception.hpp"
 #include "ExtrusionEntity.hpp"
 
 namespace Slic3r {
@@ -27,11 +28,11 @@ enum FlowRole {
     frSupportMaterialInterface,
 };
 
-class FlowError : public std::invalid_argument
+class FlowError : public Slic3r::InvalidArgument
 {
 public:
-	FlowError(const std::string& what_arg) : invalid_argument(what_arg) {}
-	FlowError(const char* what_arg) : invalid_argument(what_arg) {}
+	FlowError(const std::string& what_arg) : Slic3r::InvalidArgument(what_arg) {}
+	FlowError(const char* what_arg) : Slic3r::InvalidArgument(what_arg) {}
 };
 
 class FlowErrorNegativeSpacing : public FlowError
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 66dd0049c..46a6c02af 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1,4 +1,5 @@
 #include "../libslic3r.h"
+#include "../Exception.hpp"
 #include "../Model.hpp"
 #include "../Utils.hpp"
 #include "../GCode.hpp"
@@ -123,11 +124,11 @@ const char* INVALID_OBJECT_TYPES[] =
     "other"
 };
 
-class version_error : public std::runtime_error
+class version_error : public Slic3r::FileIOError
 {
 public:
-    version_error(const std::string& what_arg) : std::runtime_error(what_arg) {}
-    version_error(const char* what_arg) : std::runtime_error(what_arg) {}
+    version_error(const std::string& what_arg) : Slic3r::FileIOError(what_arg) {}
+    version_error(const char* what_arg) : Slic3r::FileIOError(what_arg) {}
 };
 
 const char* get_attribute_value_charptr(const char** attributes, unsigned int attributes_size, const char* attribute_key)
@@ -607,7 +608,7 @@ namespace Slic3r {
                     {
                         // ensure the zip archive is closed and rethrow the exception
                         close_zip_reader(&archive);
-                        throw std::runtime_error(e.what());
+                        throw Slic3r::FileIOError(e.what());
                     }
                 }
             }
@@ -780,7 +781,7 @@ namespace Slic3r {
                 {
                     char error_buf[1024];
                     ::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
-                    throw std::runtime_error(error_buf);
+                    throw Slic3r::FileIOError(error_buf);
                 }
 
                 return n;
@@ -789,7 +790,7 @@ namespace Slic3r {
         catch (const version_error& e)
         {
             // rethrow the exception
-            throw std::runtime_error(e.what());
+            throw Slic3r::FileIOError(e.what());
         }
         catch (std::exception& e)
         {
@@ -2360,9 +2361,9 @@ namespace Slic3r {
                 continue;
 
 			if (!volume->mesh().repaired)
-				throw std::runtime_error("store_3mf() requires repair()");
+				throw Slic3r::FileIOError("store_3mf() requires repair()");
 			if (!volume->mesh().has_shared_vertices())
-				throw std::runtime_error("store_3mf() requires shared vertices");
+				throw Slic3r::FileIOError("store_3mf() requires shared vertices");
 
             volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
 
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index af7b9b1b6..1a706afa9 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -7,6 +7,7 @@
 #include <boost/nowide/cstdio.hpp>
 
 #include "../libslic3r.h"
+#include "../Exception.hpp"
 #include "../Model.hpp"
 #include "../GCode.hpp"
 #include "../PrintConfig.hpp"
@@ -923,7 +924,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
             {
                 char error_buf[1024];
                 ::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", XML_ErrorString(XML_GetErrorCode(data->parser)), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
-                throw std::runtime_error(error_buf);
+                throw Slic3r::FileIOError(error_buf);
             }
 
             return n;
@@ -948,9 +949,9 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
     if (check_version && (ctx.m_version > VERSION_AMF_COMPATIBLE))
     {
         // std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
-        // throw std::runtime_error(msg.c_str());
+        // throw Slic3r::FileIOError(msg.c_str());
         const std::string msg = (boost::format(_(L("The selected amf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str();
-        throw std::runtime_error(msg);
+        throw Slic3r::FileIOError(msg);
     }
 
     return true;
@@ -994,7 +995,7 @@ bool load_amf_archive(const char* path, DynamicPrintConfig* config, Model* model
                 {
                     // ensure the zip archive is closed and rethrow the exception
                     close_zip_reader(&archive);
-                    throw std::runtime_error(e.what());
+                    throw Slic3r::FileIOError(e.what());
                 }
 
                 break;
@@ -1147,9 +1148,9 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
         for (ModelVolume *volume : object->volumes) {
             vertices_offsets.push_back(num_vertices);
             if (! volume->mesh().repaired)
-                throw std::runtime_error("store_amf() requires repair()");
+                throw Slic3r::FileIOError("store_amf() requires repair()");
 			if (! volume->mesh().has_shared_vertices())
-				throw std::runtime_error("store_amf() requires shared vertices");
+				throw Slic3r::FileIOError("store_amf() requires shared vertices");
             const indexed_triangle_set &its = volume->mesh().its;
             const Transform3d& matrix = volume->get_matrix();
             for (size_t i = 0; i < its.vertices.size(); ++i) {
diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
index d6f87197d..e2c38d957 100644
--- a/src/libslic3r/Format/PRUS.cpp
+++ b/src/libslic3r/Format/PRUS.cpp
@@ -147,7 +147,7 @@ static void extract_model_from_archive(
         }
     }
     if (! trafo_set)
-        throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid entry in scene.xml for " + name);
+        throw Slic3r::FileIOError(std::string("Archive ") + path + " does not contain a valid entry in scene.xml for " + name);
 
     // Extract the STL.
     StlHeader header;
@@ -266,7 +266,7 @@ static void extract_model_from_archive(
     }
 
     if (! mesh_valid)
-        throw std::runtime_error(std::string("Archive ") + path + " does not contain a valid mesh for " + name);
+        throw Slic3r::FileIOError(std::string("Archive ") + path + " does not contain a valid mesh for " + name);
 
     // Add this mesh to the model.
     ModelVolume *volume = nullptr;
@@ -303,7 +303,7 @@ bool load_prus(const char *path, Model *model)
     mz_bool res              = MZ_FALSE;
     try {
         if (!open_zip_reader(&archive, path))
-            throw std::runtime_error(std::string("Unable to init zip reader for ") + path);
+            throw Slic3r::FileIOError(std::string("Unable to init zip reader for ") + path);
         std::vector<char>           scene_xml_data;
         // For grouping multiple STLs into a single ModelObject for multi-material prints.
         std::map<int, ModelObject*> group_to_model_object;
@@ -316,10 +316,10 @@ bool load_prus(const char *path, Model *model)
             buffer.assign((size_t)stat.m_uncomp_size, 0);
             res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (char*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
             if (res == MZ_FALSE)
-                std::runtime_error(std::string("Error while extracting a file from ") + path);
+                throw Slic3r::FileIOError(std::string("Error while extracting a file from ") + path);
             if (strcmp(stat.m_filename, "scene.xml") == 0) {
                 if (! scene_xml_data.empty())
-                    throw std::runtime_error(std::string("Multiple scene.xml were found in the archive.") + path);
+                    throw Slic3r::FileIOError(std::string("Multiple scene.xml were found in the archive.") + path);
                 scene_xml_data = std::move(buffer);
             } else if (boost::iends_with(stat.m_filename, ".stl")) {
                 // May throw std::exception
diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp
index ff1af5d8b..274f84f00 100644
--- a/src/libslic3r/Format/SL1.cpp
+++ b/src/libslic3r/Format/SL1.cpp
@@ -10,6 +10,7 @@
 
 #include <sstream>
 
+#include "libslic3r/Exception.hpp"
 #include "libslic3r/SlicesToTriangleMesh.hpp"
 #include "libslic3r/MarchingSquares.hpp"
 #include "libslic3r/ClipperUtils.hpp"
@@ -64,7 +65,7 @@ boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
 
     if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename,
                                            buf.data(), buf.size(), 0))
-        throw std::runtime_error(zip.get_errorstr());
+        throw Slic3r::FileIOError(zip.get_errorstr());
 
     boost::property_tree::ptree tree;
     std::stringstream ss(buf);
@@ -80,7 +81,7 @@ PNGBuffer read_png(const mz_zip_archive_file_stat &entry,
 
     if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename,
                                            buf.data(), buf.size(), 0))
-        throw std::runtime_error(zip.get_errorstr());
+        throw Slic3r::FileIOError(zip.get_errorstr());
 
     return {std::move(buf), (name.empty() ? entry.m_filename : name)};
 }
@@ -94,7 +95,7 @@ ArchiveData extract_sla_archive(const std::string &zipfname,
     struct Arch: public MZ_Archive {
         Arch(const std::string &fname) {
             if (!open_zip_reader(&arch, fname))
-                throw std::runtime_error(get_errorstr());
+                throw Slic3r::FileIOError(get_errorstr());
         }
 
         ~Arch() { close_zip_reader(&arch); }
@@ -202,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
 
     if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
         !opt_mirror_x || !opt_mirror_y || !opt_orient)
-        throw std::runtime_error("Invalid SL1 file");
+        throw Slic3r::FileIOError("Invalid SL1 file");
 
     RasterParams rstp;
 
@@ -228,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg)
     auto *opt_init_layerh = cfg.option<ConfigOptionFloat>("initial_layer_height");
 
     if (!opt_layerh || !opt_init_layerh)
-        throw std::runtime_error("Invalid SL1 file");
+        throw Slic3r::FileIOError("Invalid SL1 file");
 
     return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
 }
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 0c4e76cd7..1788250f8 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -1,6 +1,7 @@
 #include "libslic3r.h"
 #include "I18N.hpp"
 #include "GCode.hpp"
+#include "Exception.hpp"
 #include "ExtrusionEntity.hpp"
 #include "EdgeGrid.hpp"
 #include "Geometry.hpp"
@@ -286,7 +287,7 @@ namespace Slic3r {
     std::string WipeTowerIntegration::append_tcr(GCode& gcodegen, const WipeTower::ToolChangeResult& tcr, int new_extruder_id, double z) const
     {
         if (new_extruder_id != -1 && new_extruder_id != tcr.new_tool)
-            throw std::invalid_argument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect.");
+            throw Slic3r::InvalidArgument("Error: WipeTowerIntegration::append_tcr was asked to do a toolchange it didn't expect.");
 
         std::string gcode;
 
@@ -539,7 +540,7 @@ namespace Slic3r {
         if (!m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
             if (m_layer_idx < (int)m_tool_changes.size()) {
                 if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
-                    throw std::runtime_error("Wipe tower generation failed, possibly due to empty first layer.");
+                    throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
 
 
                 // Calculate where the wipe tower layer will be printed. -1 means that print z will not change,
@@ -628,7 +629,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
         // Check that there are extrusions on the very first layer.
         if (layers_to_print.size() == 1u) {
             if (!has_extrusions)
-                throw std::runtime_error(_(L("There is an object with no extrusions on the first layer.")));
+                throw Slic3r::RuntimeError(_(L("There is an object with no extrusions on the first layer.")));
         }
 
         // In case there are extrusions on this layer, check there is a layer to lay it on.
@@ -749,7 +750,7 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
 
     FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb");
     if (file == nullptr)
-        throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
+        throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
 
 #if !ENABLE_GCODE_VIEWER
     m_enable_analyzer = preview_data != nullptr;
@@ -762,7 +763,7 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
         if (ferror(file)) {
             fclose(file);
             boost::nowide::remove(path_tmp.c_str());
-            throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
+            throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
         }
     } catch (std::exception & /* ex */) {
         // Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
@@ -783,7 +784,7 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
         msg += "        !!!!! Failed to process the custom G-code template ...\n";
         msg += "and\n";
         msg += "        !!!!! End of an error report for the custom G-code template ...\n";
-        throw std::runtime_error(msg);
+        throw Slic3r::RuntimeError(msg);
     }
 
 #if ENABLE_GCODE_VIEWER
@@ -817,7 +818,7 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
 #endif // ENABLE_GCODE_VIEWER
 
     if (rename_file(path_tmp, path))
-        throw std::runtime_error(
+        throw Slic3r::RuntimeError(
             std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
             "Is " + path_tmp + " locked?" + '\n');
 
@@ -3006,7 +3007,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string des
     else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity))
         return this->extrude_loop(*loop, description, speed, lower_layer_edge_grid);
     else
-        throw std::invalid_argument("Invalid argument supplied to extrude()");
+        throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()");
     return "";
 }
 
@@ -3211,7 +3212,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
         } else if (path.role() == erGapFill) {
             speed = m_config.get_abs_value("gap_fill_speed");
         } else {
-            throw std::invalid_argument("Invalid speed");
+            throw Slic3r::InvalidArgument("Invalid speed");
         }
     }
     if (this->on_first_layer())
@@ -3632,7 +3633,7 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
     	perimeters_or_infills_overrides = &infills_overrides;
         break;
     default:
-    	throw std::invalid_argument("Unknown parameter!");
+    	throw Slic3r::InvalidArgument("Unknown parameter!");
     }
 
     // First we append the entities, there are eec->entities.size() of them:
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index db69f4f0b..0a5617559 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -319,13 +319,13 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
 {
     boost::nowide::ifstream in(filename);
     if (!in.good())
-        throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
+        throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
 
     // temporary file to contain modified gcode
     std::string out_path = filename + ".postprocess";
     FILE* out = boost::nowide::fopen(out_path.c_str(), "wb");
     if (out == nullptr)
-        throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
+        throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
 
     auto time_in_minutes = [](float time_in_seconds) {
         return int(::roundf(time_in_seconds / 60.0f));
@@ -418,7 +418,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
             in.close();
             fclose(out);
             boost::nowide::remove(out_path.c_str());
-            throw std::runtime_error(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
+            throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
         }
         export_line.clear();
     };
@@ -426,7 +426,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
     while (std::getline(in, gcode_line)) {
         if (!in.good()) {
             fclose(out);
-            throw std::runtime_error(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
+            throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
         }
 
         gcode_line += "\n";
@@ -460,7 +460,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
     in.close();
 
     if (rename_file(out_path, filename))
-        throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
+        throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
             "Is " + out_path + " locked?" + '\n');
 }
 
diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp
index 25982959b..17aa76fb9 100644
--- a/src/libslic3r/GCode/PostProcessor.cpp
+++ b/src/libslic3r/GCode/PostProcessor.cpp
@@ -79,7 +79,7 @@ static DWORD execute_process_winapi(const std::wstring &command_line)
 	if (! ::CreateProcessW(
             nullptr /* lpApplicationName */, (LPWSTR)command_line.c_str(), nullptr /* lpProcessAttributes */, nullptr /* lpThreadAttributes */, false /* bInheritHandles */,
 			CREATE_UNICODE_ENVIRONMENT /* | CREATE_NEW_CONSOLE */ /* dwCreationFlags */, (LPVOID)envstr.c_str(), nullptr /* lpCurrentDirectory */, &startup_info, &process_info))
-		throw std::runtime_error(std::string("Failed starting the script ") + boost::nowide::narrow(command_line) + ", Win32 error: " + std::to_string(int(::GetLastError())));
+		throw Slic3r::RuntimeError(std::string("Failed starting the script ") + boost::nowide::narrow(command_line) + ", Win32 error: " + std::to_string(int(::GetLastError())));
 	::WaitForSingleObject(process_info.hProcess, INFINITE);
 	ULONG rc = 0;
 	::GetExitCodeProcess(process_info.hProcess, &rc);
@@ -98,13 +98,13 @@ static int run_script(const std::string &script, const std::string &gcode, std::
     LPWSTR *szArglist = CommandLineToArgvW(boost::nowide::widen(script).c_str(), &nArgs);
     if (szArglist == nullptr || nArgs <= 0) {
         // CommandLineToArgvW failed. Maybe the command line escapment is invalid?
-		throw std::runtime_error(std::string("Post processing script ") + script + " on file " + gcode + " failed. CommandLineToArgvW() refused to parse the command line path.");
+		throw Slic3r::RuntimeError(std::string("Post processing script ") + script + " on file " + gcode + " failed. CommandLineToArgvW() refused to parse the command line path.");
     }
 
     std::wstring command_line;
     std::wstring command = szArglist[0];
 	if (! boost::filesystem::exists(boost::filesystem::path(command)))
-		throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command));
+		throw Slic3r::RuntimeError(std::string("The configured post-processing script does not exist: ") + boost::nowide::narrow(command));
     if (boost::iends_with(command, L".pl")) {
         // This is a perl script. Run it through the perl interpreter.
         // The current process may be slic3r.exe or slic3r-console.exe.
@@ -115,7 +115,7 @@ static int run_script(const std::string &script, const std::string &gcode, std::
         boost::filesystem::path path_perl = path_exe.parent_path() / "perl" / "perl.exe";
         if (! boost::filesystem::exists(path_perl)) {
 			LocalFree(szArglist);
-			throw std::runtime_error(std::string("Perl interpreter ") + path_perl.string() + " does not exist.");
+			throw Slic3r::RuntimeError(std::string("Perl interpreter ") + path_perl.string() + " does not exist.");
         }
         // Replace it with the current perl interpreter.
         quote_argv_winapi(boost::nowide::widen(path_perl.string()), command_line);
@@ -187,7 +187,7 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config
     config.setenv_();
     auto gcode_file = boost::filesystem::path(path);
     if (! boost::filesystem::exists(gcode_file))
-        throw std::runtime_error(std::string("Post-processor can't find exported gcode file"));
+        throw Slic3r::RuntimeError(std::string("Post-processor can't find exported gcode file"));
 
     for (const std::string &scripts : config.post_process.values) {
 		std::vector<std::string> lines;
@@ -205,7 +205,7 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config
                 const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str()
                     : (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str();
                 BOOST_LOG_TRIVIAL(error) << msg;
-                throw std::runtime_error(msg);
+                throw Slic3r::RuntimeError(msg);
             }
         }
     }
diff --git a/src/libslic3r/GCode/PressureEqualizer.cpp b/src/libslic3r/GCode/PressureEqualizer.cpp
index 3b2a58a88..33601e5e9 100644
--- a/src/libslic3r/GCode/PressureEqualizer.cpp
+++ b/src/libslic3r/GCode/PressureEqualizer.cpp
@@ -148,7 +148,7 @@ static inline int parse_int(const char *&line)
     char *endptr = NULL;
     long result = strtol(line, &endptr, 10);
     if (endptr == NULL || !is_ws_or_eol(*endptr))
-        throw std::runtime_error("PressureEqualizer: Error parsing an int");
+        throw Slic3r::RuntimeError("PressureEqualizer: Error parsing an int");
     line = endptr;
     return int(result);
 };
@@ -160,7 +160,7 @@ static inline float parse_float(const char *&line)
     char *endptr = NULL;
     float result = strtof(line, &endptr);
     if (endptr == NULL || !is_ws_or_eol(*endptr))
-        throw std::runtime_error("PressureEqualizer: Error parsing a float");
+        throw Slic3r::RuntimeError("PressureEqualizer: Error parsing a float");
     line = endptr;
     return result;
 };
@@ -229,7 +229,7 @@ bool PressureEqualizer::process_line(const char *line, const size_t len, GCodeLi
                     assert(false);
                 }
                 if (i == -1)
-                    throw std::runtime_error(std::string("GCode::PressureEqualizer: Invalid axis for G0/G1: ") + axis);
+                    throw Slic3r::RuntimeError(std::string("GCode::PressureEqualizer: Invalid axis for G0/G1: ") + axis);
                 buf.pos_provided[i] = true;
                 new_pos[i] = parse_float(line);
                 if (i == 3 && m_config->use_relative_e_distances.value)
@@ -298,7 +298,7 @@ bool PressureEqualizer::process_line(const char *line, const size_t len, GCodeLi
                     set = true;
                     break;
                 default:
-                    throw std::runtime_error(std::string("GCode::PressureEqualizer: Incorrect axis in a G92 G-code: ") + axis);
+                    throw Slic3r::RuntimeError(std::string("GCode::PressureEqualizer: Incorrect axis in a G92 G-code: ") + axis);
                 }
                 eatws(line);
             }
diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp
index 4a6624531..a86411519 100644
--- a/src/libslic3r/GCode/PrintExtents.cpp
+++ b/src/libslic3r/GCode/PrintExtents.cpp
@@ -94,7 +94,7 @@ static BoundingBoxf extrusionentity_extents(const ExtrusionEntity *extrusion_ent
     auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
     if (extrusion_entity_collection != nullptr)
         return extrusionentity_extents(*extrusion_entity_collection);
-    throw std::runtime_error("Unexpected extrusion_entity type in extrusionentity_extents()");
+    throw Slic3r::RuntimeError("Unexpected extrusion_entity type in extrusionentity_extents()");
     return BoundingBoxf();
 }
 
diff --git a/src/libslic3r/GCodeSender.cpp b/src/libslic3r/GCodeSender.cpp
index 9567e07d2..7bda29992 100644
--- a/src/libslic3r/GCodeSender.cpp
+++ b/src/libslic3r/GCodeSender.cpp
@@ -153,7 +153,7 @@ GCodeSender::set_baud_rate(unsigned int baud_rate)
 		if (::tcsetattr(handle, TCSAFLUSH, &ios) != 0)
 			printf("Failed to set baud rate: %s\n", strerror(errno));
 #else
-        //throw invalid_argument ("OS does not currently support custom bauds");
+        //throw Slic3r::InvalidArgument("OS does not currently support custom bauds");
 #endif
     }
 }
diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp
index aa9ee2f64..a3e20ca2f 100644
--- a/src/libslic3r/GCodeTimeEstimator.cpp
+++ b/src/libslic3r/GCodeTimeEstimator.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "GCodeTimeEstimator.hpp"
 #include "Utils.hpp"
 #include <boost/bind.hpp>
@@ -254,13 +255,13 @@ namespace Slic3r {
     {
         boost::nowide::ifstream in(filename);
         if (!in.good())
-            throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
+            throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
 
         std::string path_tmp = filename + ".postprocess";
 
         FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
         if (out == nullptr)
-            throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
+            throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
 
         std::string normal_time_mask = "M73 P%s R%s\n";
         std::string silent_time_mask = "M73 Q%s S%s\n";
@@ -278,7 +279,7 @@ namespace Slic3r {
                 in.close();
                 fclose(out);
                 boost::nowide::remove(path_tmp.c_str());
-                throw std::runtime_error(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
+                throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
             }
             export_line.clear();
         };
@@ -326,7 +327,7 @@ namespace Slic3r {
             if (!in.good())
             {
                 fclose(out);
-                throw std::runtime_error(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
+                throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
             }
 
             // check tags
@@ -383,7 +384,7 @@ namespace Slic3r {
         in.close();
 
         if (rename_file(path_tmp, filename))
-            throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
+            throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
                 "Is " + path_tmp + " locked?" + '\n');
 
         return true;
diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp
index 00a4ad47c..3b9fcd617 100644
--- a/src/libslic3r/Geometry.cpp
+++ b/src/libslic3r/Geometry.cpp
@@ -1,4 +1,5 @@
 #include "libslic3r.h"
+#include "Exception.hpp"
 #include "Geometry.hpp"
 #include "ClipperUtils.hpp"
 #include "ExPolygon.hpp"
@@ -471,7 +472,7 @@ Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const Bo
     size_t cellw = size_t(floor((bed_bbox.size()(0) + gap) / cell_size(0)));
     size_t cellh = size_t(floor((bed_bbox.size()(1) + gap) / cell_size(1)));
     if (num_parts > cellw * cellh)
-        throw std::invalid_argument("%zu parts won't fit in your print area!\n", num_parts);
+        throw Slic3r::InvalidArgument("%zu parts won't fit in your print area!\n", num_parts);
     
     // Get a bounding box of cellw x cellh cells, centered at the center of the bed.
     Vec2d       cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap);
diff --git a/src/libslic3r/MeshBoolean.cpp b/src/libslic3r/MeshBoolean.cpp
index 66167c720..dd34b2830 100644
--- a/src/libslic3r/MeshBoolean.cpp
+++ b/src/libslic3r/MeshBoolean.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "MeshBoolean.hpp"
 #include "libslic3r/TriangleMesh.hpp"
 #undef PI
@@ -136,7 +137,7 @@ template<class _Mesh> void triangle_mesh_to_cgal(const TriangleMesh &M, _Mesh &o
     if(CGAL::is_closed(out))
         CGALProc::orient_to_bound_a_volume(out);
     else
-        std::runtime_error("Mesh not watertight");
+        throw Slic3r::RuntimeError("Mesh not watertight");
 }
 
 inline Vec3d to_vec3d(const _EpicMesh::Point &v)
@@ -222,7 +223,7 @@ template<class Op> void _cgal_do(Op &&op, CGALMesh &A, CGALMesh &B)
     }
 
     if (! success)
-        throw std::runtime_error("CGAL mesh boolean operation failed.");
+        throw Slic3r::RuntimeError("CGAL mesh boolean operation failed.");
 }
 
 void minus(CGALMesh &A, CGALMesh &B) { _cgal_do(_cgal_diff, A, B); }
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 67fe63871..dc06e3102 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "Model.hpp"
 #include "ModelArrange.hpp"
 #include "Geometry.hpp"
@@ -116,13 +117,13 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
     else if (boost::algorithm::iends_with(input_file, ".prusa"))
         result = load_prus(input_file.c_str(), &model);
     else
-        throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension.");
+        throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension.");
 
     if (! result)
-        throw std::runtime_error("Loading of a model file failed.");
+        throw Slic3r::RuntimeError("Loading of a model file failed.");
 
     if (model.objects.empty())
-        throw std::runtime_error("The supplied file couldn't be read because it's empty");
+        throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty");
     
     for (ModelObject *o : model.objects)
         o->input_file = input_file;
@@ -146,13 +147,13 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
     else if (boost::algorithm::iends_with(input_file, ".zip.amf"))
         result = load_amf(input_file.c_str(), config, &model, check_version);
     else
-        throw std::runtime_error("Unknown file format. Input file must have .3mf or .zip.amf extension.");
+        throw Slic3r::RuntimeError("Unknown file format. Input file must have .3mf or .zip.amf extension.");
 
     if (!result)
-        throw std::runtime_error("Loading of a model file failed.");
+        throw Slic3r::RuntimeError("Loading of a model file failed.");
 
     if (model.objects.empty())
-        throw std::runtime_error("The supplied file couldn't be read because it's empty");
+        throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty");
 
     for (ModelObject *o : model.objects)
     {
@@ -817,7 +818,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
         m_raw_bounding_box_valid = true;
         m_raw_bounding_box.reset();
         if (this->instances.empty())
-            throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
+            throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances");
 
         const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
         for (const ModelVolume *v : this->volumes)
diff --git a/src/libslic3r/ModelArrange.hpp b/src/libslic3r/ModelArrange.hpp
index afe146d43..124c5c018 100644
--- a/src/libslic3r/ModelArrange.hpp
+++ b/src/libslic3r/ModelArrange.hpp
@@ -20,7 +20,7 @@ using VirtualBedFn = std::function<void(arrangement::ArrangePolygon&)>;
 
 [[noreturn]] inline void throw_if_out_of_bed(arrangement::ArrangePolygon&) 
 {
-    throw std::runtime_error("Objects could not fit on the bed");
+    throw Slic3r::RuntimeError("Objects could not fit on the bed");
 }
 
 ArrangePolygons get_arrange_polys(const Model &model, ModelInstancePtrs &instances);
diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp
index 527d82b4c..0434e3a0a 100644
--- a/src/libslic3r/PlaceholderParser.cpp
+++ b/src/libslic3r/PlaceholderParser.cpp
@@ -1,4 +1,5 @@
 #include "PlaceholderParser.hpp"
+#include "Exception.hpp"
 #include "Flow.hpp"
 #include <cstring>
 #include <ctime>
@@ -1303,7 +1304,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
 	if (!context.error_message.empty()) {
         if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
             context.error_message += '\n';
-        throw std::runtime_error(context.error_message);
+        throw Slic3r::RuntimeError(context.error_message);
     }
     return output;
 }
@@ -1319,7 +1320,7 @@ std::string PlaceholderParser::process(const std::string &templ, unsigned int cu
 }
 
 // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
-// Throws std::runtime_error on syntax or runtime error.
+// Throws Slic3r::RuntimeError on syntax or runtime error.
 bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override)
 {
     client::MyContext context;
diff --git a/src/libslic3r/PlaceholderParser.hpp b/src/libslic3r/PlaceholderParser.hpp
index d744dba22..14be020ac 100644
--- a/src/libslic3r/PlaceholderParser.hpp
+++ b/src/libslic3r/PlaceholderParser.hpp
@@ -40,11 +40,11 @@ public:
 	const DynamicConfig*	external_config() const  			{ return m_external_config; }
 
     // Fill in the template using a macro processing language.
-    // Throws std::runtime_error on syntax or runtime error.
+    // Throws Slic3r::RuntimeError on syntax or runtime error.
     std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const;
     
     // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
-    // Throws std::runtime_error on syntax or runtime error.
+    // Throws Slic3r::RuntimeError on syntax or runtime error.
     static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);
 
     // Update timestamp, year, month, day, hour, minute, second variables at the provided config.
diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp
index 48e63dab3..fc83ae8d4 100644
--- a/src/libslic3r/Polygon.cpp
+++ b/src/libslic3r/Polygon.cpp
@@ -1,5 +1,6 @@
 #include "BoundingBox.hpp"
 #include "ClipperUtils.hpp"
+#include "Exception.hpp"
 #include "Polygon.hpp"
 #include "Polyline.hpp"
 
@@ -16,7 +17,7 @@ Polyline Polygon::split_at_vertex(const Point &point) const
     for (const Point &pt : this->points)
         if (pt == point)
             return this->split_at_index(int(&pt - &this->points.front()));
-    throw std::invalid_argument("Point not found");
+    throw Slic3r::InvalidArgument("Point not found");
     return Polyline();
 }
 
diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp
index 26aad83d2..d24788c7b 100644
--- a/src/libslic3r/Polyline.cpp
+++ b/src/libslic3r/Polyline.cpp
@@ -1,5 +1,6 @@
 #include "BoundingBox.hpp"
 #include "Polyline.hpp"
+#include "Exception.hpp"
 #include "ExPolygon.hpp"
 #include "ExPolygonCollection.hpp"
 #include "Line.hpp"
@@ -19,7 +20,7 @@ Polyline::operator Polylines() const
 Polyline::operator Line() const
 {
     if (this->points.size() > 2) 
-        throw std::invalid_argument("Can't convert polyline with more than two points to a line");
+        throw Slic3r::InvalidArgument("Can't convert polyline with more than two points to a line");
     return Line(this->points.front(), this->points.back());
 }
 
@@ -207,7 +208,7 @@ BoundingBox get_extents(const Polylines &polylines)
 const Point& leftmost_point(const Polylines &polylines)
 {
     if (polylines.empty())
-        throw std::invalid_argument("leftmost_point() called on empty PolylineCollection");
+        throw Slic3r::InvalidArgument("leftmost_point() called on empty PolylineCollection");
     Polylines::const_iterator it = polylines.begin();
     const Point *p = &it->leftmost_point();
     for (++ it; it != polylines.end(); ++it) {
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index 284c37435..18a6e387c 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -1,5 +1,6 @@
 #include <cassert>
 
+#include "Exception.hpp"
 #include "Preset.hpp"
 #include "AppConfig.hpp"
 
@@ -107,7 +108,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
     const std::string id = path.stem().string();
 
     if (! boost::filesystem::exists(path)) {
-        throw std::runtime_error((boost::format("Cannot load Vendor Config Bundle `%1%`: File not found: `%2%`.") % id % path).str());
+        throw Slic3r::RuntimeError((boost::format("Cannot load Vendor Config Bundle `%1%`: File not found: `%2%`.") % id % path).str());
     }
 
     VendorProfile res(id);
@@ -117,7 +118,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
     {
         auto res = tree.find(key);
         if (res == tree.not_found()) {
-            throw std::runtime_error((boost::format("Vendor Config Bundle `%1%` is not valid: Missing secion or key: `%2%`.") % id % key).str());
+            throw Slic3r::RuntimeError((boost::format("Vendor Config Bundle `%1%` is not valid: Missing secion or key: `%2%`.") % id % key).str());
         }
         return res;
     };
@@ -129,7 +130,7 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
     auto config_version_str = get_or_throw(vendor_section, "config_version")->second.data();
     auto config_version = Semver::parse(config_version_str);
     if (! config_version) {
-        throw std::runtime_error((boost::format("Vendor Config Bundle `%1%` is not valid: Cannot parse config_version: `%2%`.") % id % config_version_str).str());
+        throw Slic3r::RuntimeError((boost::format("Vendor Config Bundle `%1%` is not valid: Cannot parse config_version: `%2%`.") % id % config_version_str).str());
     } else {
         res.config_version = std::move(*config_version);
     }
@@ -672,9 +673,9 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
                             preset.file << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
                     preset.loaded = true;
                 } catch (const std::ifstream::failure &err) {
-                    throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
+                    throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
                 } catch (const std::runtime_error &err) {
-                    throw std::runtime_error(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
+                    throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
                 }
                 presets_loaded.emplace_back(preset);
             } catch (const std::runtime_error &err) {
@@ -686,7 +687,7 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
     std::sort(m_presets.begin() + m_num_default_presets, m_presets.end());
     this->select_preset(first_visible_idx());
     if (! errors_cummulative.empty())
-        throw std::runtime_error(errors_cummulative);
+        throw Slic3r::RuntimeError(errors_cummulative);
 }
 
 // Load a preset from an already parsed config file, insert it into the sorted sequence of presets
@@ -1557,10 +1558,10 @@ void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const
                     printer.loaded = true;
                 }
                 catch (const std::ifstream::failure& err) {
-                    throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + printer.file + "\n\tReason: " + err.what());
+                    throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + printer.file + "\n\tReason: " + err.what());
                 }
                 catch (const std::runtime_error& err) {
-                    throw std::runtime_error(std::string("Failed loading the preset file: ") + printer.file + "\n\tReason: " + err.what());
+                    throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + printer.file + "\n\tReason: " + err.what());
                 }
                 printers_loaded.emplace_back(printer);
             }
@@ -1572,7 +1573,7 @@ void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const
     m_printers.insert(m_printers.end(), std::make_move_iterator(printers_loaded.begin()), std::make_move_iterator(printers_loaded.end()));
     std::sort(m_printers.begin(), m_printers.end());
     if (!errors_cummulative.empty())
-        throw std::runtime_error(errors_cummulative);
+        throw Slic3r::RuntimeError(errors_cummulative);
 }
 
 // if there is saved user presets, contains information about "Print Host upload",
diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp
index ac1b0a717..c100e6971 100644
--- a/src/libslic3r/PresetBundle.cpp
+++ b/src/libslic3r/PresetBundle.cpp
@@ -157,7 +157,7 @@ void PresetBundle::setup_directories()
         subdir.make_preferred();
         if (! boost::filesystem::is_directory(subdir) && 
             ! boost::filesystem::create_directory(subdir))
-            throw std::runtime_error(std::string("Slic3r was unable to create its data directory at ") + subdir.string());
+            throw Slic3r::RuntimeError(std::string("Slic3r was unable to create its data directory at ") + subdir.string());
     }
 }
 
@@ -207,7 +207,7 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
     this->update_multi_material_filament_presets();
     this->update_compatible(PresetSelectCompatibleType::Never);
     if (! errors_cummulative.empty())
-        throw std::runtime_error(errors_cummulative);
+        throw Slic3r::RuntimeError(errors_cummulative);
 
     this->load_selections(config, preferred_model_id);
 }
@@ -679,21 +679,21 @@ void PresetBundle::load_config_file(const std::string &path)
         boost::nowide::ifstream ifs(path);
         boost::property_tree::read_ini(ifs, tree);
     } catch (const std::ifstream::failure &err) {
-        throw std::runtime_error(std::string("The Config Bundle cannot be loaded: ") + path + "\n\tReason: " + err.what());
+        throw Slic3r::RuntimeError(std::string("The Config Bundle cannot be loaded: ") + path + "\n\tReason: " + err.what());
     } catch (const boost::property_tree::file_parser_error &err) {
-        throw std::runtime_error((boost::format("Failed loading the Config Bundle \"%1%\": %2% at line %3%")
+        throw Slic3r::RuntimeError((boost::format("Failed loading the Config Bundle \"%1%\": %2% at line %3%")
         	% err.filename() % err.message() % err.line()).str());
     } catch (const std::runtime_error &err) {
-        throw std::runtime_error(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what());
+        throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what());
     }
 
     // 2) Continue based on the type of the configuration file.
     ConfigFileType config_file_type = guess_config_file_type(tree);
     switch (config_file_type) {
     case CONFIG_FILE_TYPE_UNKNOWN:
-        throw std::runtime_error(std::string("Unknown configuration file type: ") + path);   
+        throw Slic3r::RuntimeError(std::string("Unknown configuration file type: ") + path);   
     case CONFIG_FILE_TYPE_APP_CONFIG:
-        throw std::runtime_error(std::string("Invalid configuration file: ") + path + ". This is an application config file.");
+        throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + path + ". This is an application config file.");
 	case CONFIG_FILE_TYPE_CONFIG:
 	{
 		// Initialize a config from full defaults.
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 50b752984..a73b7016f 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -1,5 +1,6 @@
 #include "clipper/clipper_z.hpp"
 
+#include "Exception.hpp"
 #include "Print.hpp"
 #include "BoundingBox.hpp"
 #include "ClipperUtils.hpp"
@@ -1507,7 +1508,7 @@ BoundingBox Print::total_bounding_box() const
 double Print::skirt_first_layer_height() const
 {
     if (m_objects.empty()) 
-        throw std::invalid_argument("skirt_first_layer_height() can't be called without PrintObjects");
+        throw Slic3r::InvalidArgument("skirt_first_layer_height() can't be called without PrintObjects");
     return m_objects.front()->config().get_abs_value("first_layer_height");
 }
 
@@ -1603,7 +1604,7 @@ void Print::process()
         	// Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
         	m_tool_ordering = ToolOrdering(*this, -1, false);
             if (m_tool_ordering.empty() || m_tool_ordering.last_extruder() == unsigned(-1))
-                throw std::runtime_error("The print is empty. The model is not printable with current print settings.");
+                throw Slic3r::RuntimeError("The print is empty. The model is not printable with current print settings.");
         }
         this->set_done(psWipeTower);
     }
diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp
index ab6ca3d35..7cdf6448c 100644
--- a/src/libslic3r/PrintBase.cpp
+++ b/src/libslic3r/PrintBase.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "PrintBase.hpp"
 
 #include <boost/filesystem.hpp>
@@ -68,7 +69,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
             filename = boost::filesystem::change_extension(filename, default_ext);
         return filename.string();
     } catch (std::runtime_error &err) {
-        throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
+        throw Slic3r::RuntimeError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
     }
 }
 
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index e2dba5bb2..30c070338 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "Print.hpp"
 #include "BoundingBox.hpp"
 #include "ClipperUtils.hpp"
@@ -138,7 +139,7 @@ void PrintObject::slice()
             }
         });
     if (m_layers.empty())
-        throw std::runtime_error("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");    
+        throw Slic3r::RuntimeError("No layers were detected. You might want to repair your STL file(s) or check their size or thickness and retry.\n");    
     this->set_done(posSlice);
 }
 
@@ -426,7 +427,7 @@ void PrintObject::generate_support_material()
             // therefore they cannot be printed without supports.
             for (const Layer *layer : m_layers)
                 if (layer->empty())
-                    throw std::runtime_error("Levitating objects cannot be printed without supports.");
+                    throw Slic3r::RuntimeError("Levitating objects cannot be printed without supports.");
 #endif
         }
         this->set_done(posSupportMaterial);
diff --git a/src/libslic3r/PrintRegion.cpp b/src/libslic3r/PrintRegion.cpp
index b3ac6a4a5..2a75cd621 100644
--- a/src/libslic3r/PrintRegion.cpp
+++ b/src/libslic3r/PrintRegion.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "Print.hpp"
 
 namespace Slic3r {
@@ -13,7 +14,7 @@ unsigned int PrintRegion::extruder(FlowRole role) const
     else if (role == frSolidInfill || role == frTopSolidInfill)
         extruder = m_config.solid_infill_extruder;
     else
-        throw std::invalid_argument("Unknown role");
+        throw Slic3r::InvalidArgument("Unknown role");
     return extruder;
 }
 
@@ -40,7 +41,7 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
         } else if (role == frTopSolidInfill) {
             config_width = m_config.top_infill_extrusion_width;
         } else {
-            throw std::invalid_argument("Unknown role");
+            throw Slic3r::InvalidArgument("Unknown role");
         }
     }
 
diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp
index eaf969819..19bd85488 100644
--- a/src/libslic3r/SLAPrintSteps.cpp
+++ b/src/libslic3r/SLAPrintSteps.cpp
@@ -1,3 +1,4 @@
+#include <libslic3r/Exception.hpp>
 #include <libslic3r/SLAPrintSteps.hpp>
 #include <libslic3r/MeshBoolean.hpp>
 
@@ -187,7 +188,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
     }
     
     if (MeshBoolean::cgal::does_self_intersect(*holes_mesh_cgal))
-        throw std::runtime_error(L("Too much overlapping holes."));
+        throw Slic3r::RuntimeError(L("Too many overlapping holes."));
     
     auto hollowed_mesh_cgal = MeshBoolean::cgal::triangle_mesh_to_cgal(hollowed_mesh);
     
@@ -195,7 +196,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
         MeshBoolean::cgal::minus(*hollowed_mesh_cgal, *holes_mesh_cgal);
         hollowed_mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*hollowed_mesh_cgal);
     } catch (const std::runtime_error &) {
-        throw std::runtime_error(L(
+        throw Slic3r::RuntimeError(L(
             "Drilling holes into the mesh failed. "
             "This is usually caused by broken model. Try to fix it first."));
     }
@@ -241,7 +242,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
     
     if(slindex_it == po.m_slice_index.end())
         //TRN To be shown at the status bar on SLA slicing error.
-        throw std::runtime_error(
+        throw Slic3r::RuntimeError(
             L("Slicing had to be stopped due to an internal error: "
               "Inconsistent slice index."));
     
@@ -445,7 +446,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
         auto &pad_mesh = po.m_supportdata->support_tree_ptr->retrieve_mesh(sla::MeshType::Pad);
         
         if (!validate_pad(pad_mesh, pcfg))
-            throw std::runtime_error(
+            throw Slic3r::RuntimeError(
                     L("No pad can be generated for this model with the "
                       "current configuration"));
         
@@ -613,7 +614,7 @@ void SLAPrint::Steps::initialize_printer_input()
         
         for(const SliceRecord& slicerecord : o->get_slice_index()) {
             if (!slicerecord.is_valid())
-                throw std::runtime_error(
+                throw Slic3r::RuntimeError(
                     L("There are unprintable objects. Try to "
                       "adjust support settings to make the "
                       "objects printable."));
diff --git a/src/libslic3r/Semver.hpp b/src/libslic3r/Semver.hpp
index 24ca74f83..f55fa9f9f 100644
--- a/src/libslic3r/Semver.hpp
+++ b/src/libslic3r/Semver.hpp
@@ -10,6 +10,8 @@
 
 #include "semver/semver.h"
 
+#include "Exception.hpp"
+
 namespace Slic3r {
 
 
@@ -38,7 +40,7 @@ public:
 	{
 		auto parsed = parse(str);
 		if (! parsed) {
-			throw std::runtime_error(std::string("Could not parse version string: ") + str);
+			throw Slic3r::RuntimeError(std::string("Could not parse version string: ") + str);
 		}
 		ver = parsed->ver;
 		parsed->ver = semver_zero();
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 49fc625af..8ba34e516 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -1,3 +1,4 @@
+#include "Exception.hpp"
 #include "TriangleMesh.hpp"
 #include "ClipperUtils.hpp"
 #include "Geometry.hpp"
@@ -420,7 +421,7 @@ std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<unsigned
 {
     // Make sure we're not operating on a broken mesh.
     if (!this->repaired)
-        throw std::runtime_error("find_unvisited_neighbors() requires repair()");
+        throw Slic3r::RuntimeError("find_unvisited_neighbors() requires repair()");
 
     // If the visited list is empty, populate it with false for every facet.
     if (facet_visited.empty())
@@ -683,7 +684,7 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
 {
     mesh = _mesh;
     if (! mesh->has_shared_vertices())
-        throw std::invalid_argument("TriangleMeshSlicer was passed a mesh without shared vertices.");
+        throw Slic3r::InvalidArgument("TriangleMeshSlicer was passed a mesh without shared vertices.");
 
     throw_on_cancel();
     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp
index 02f022083..7a95829cd 100644
--- a/src/libslic3r/Zipper.cpp
+++ b/src/libslic3r/Zipper.cpp
@@ -1,5 +1,6 @@
 #include <exception>
 
+#include "Exception.hpp"
 #include "Zipper.hpp"
 #include "miniz_extension.hpp"
 #include <boost/log/trivial.hpp>
@@ -29,7 +30,7 @@ public:
 
     SLIC3R_NORETURN void blow_up() const
     {
-        throw std::runtime_error(formatted_errorstr());
+        throw Slic3r::RuntimeError(formatted_errorstr());
     }
 
     bool is_alive()
diff --git a/src/slic3r/Config/Snapshot.cpp b/src/slic3r/Config/Snapshot.cpp
index 30596b614..45dc99874 100644
--- a/src/slic3r/Config/Snapshot.cpp
+++ b/src/slic3r/Config/Snapshot.cpp
@@ -315,7 +315,7 @@ size_t SnapshotDB::load_db()
     // Sort the snapshots by their date/time.
     std::sort(m_snapshots.begin(), m_snapshots.end(), [](const Snapshot &s1, const Snapshot &s2) { return s1.time_captured < s2.time_captured; });
     if (! errors_cummulative.empty())
-        throw std::runtime_error(errors_cummulative);
+        throw Slic3r::RuntimeError(errors_cummulative);
     return m_snapshots.size();
 }
 
@@ -339,7 +339,7 @@ static void copy_config_dir_single_level(const boost::filesystem::path &path_src
 {
     if (! boost::filesystem::is_directory(path_dst) && 
         ! boost::filesystem::create_directory(path_dst))
-        throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
+        throw Slic3r::RuntimeError(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
 
     for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
         if (Slic3r::is_ini_file(dir_entry))
@@ -429,7 +429,7 @@ const Snapshot& SnapshotDB::restore_snapshot(const std::string &id, AppConfig &a
 			this->restore_snapshot(snapshot, app_config);
 			return snapshot;
 		}
-	throw std::runtime_error(std::string("Snapshot with id " + id + " was not found."));
+	throw Slic3r::RuntimeError(std::string("Snapshot with id " + id + " was not found."));
 }
 
 void SnapshotDB::restore_snapshot(const Snapshot &snapshot, AppConfig &app_config)
@@ -501,7 +501,7 @@ boost::filesystem::path SnapshotDB::create_db_dir()
         subdir.make_preferred();
         if (! boost::filesystem::is_directory(subdir) && 
             ! boost::filesystem::create_directory(subdir))
-            throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + subdir.string());
+            throw Slic3r::RuntimeError(std::string("Slic3r was unable to create a directory at ") + subdir.string());
     }
     return snapshots_dir;
 }
diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp
index d00e4a2ab..04ce05ab5 100644
--- a/src/slic3r/Config/Version.cpp
+++ b/src/slic3r/Config/Version.cpp
@@ -324,7 +324,7 @@ std::vector<Index> Index::load_db()
         }
 
     if (! errors_cummulative.empty())
-        throw std::runtime_error(errors_cummulative);
+        throw Slic3r::RuntimeError(errors_cummulative);
     return index_db;
 }
 
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 70fec670c..ca96af49c 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -1926,7 +1926,7 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity,
                     if (extrusion_entity_collection != nullptr)
                         extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume);
                     else {
-                        throw std::runtime_error("Unexpected extrusion_entity type in to_verts()");
+                        throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
                     }
                 }
             }
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 9675db10e..9470359d0 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -41,6 +41,36 @@
 
 namespace Slic3r {
 
+bool SlicingProcessCompletedEvent::critical_error() const
+{
+	try {
+		this->rethrow_exception();
+	} catch (const Slic3r::SlicingError &ex) {
+		// Exception derived from SlicingError is non-critical.
+		return false;
+	} catch (...) {
+		return true;
+	}
+}
+
+std::string SlicingProcessCompletedEvent::format_error_message() const
+{
+	std::string error;
+	try {
+		this->rethrow_exception();
+    } catch (const std::bad_alloc& ex) {
+        wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. "
+                              "If you are sure you have enough RAM on your system, this may also be a bug and we would "
+                              "be glad if you reported it."))) % SLIC3R_APP_NAME).str());
+        error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
+    } catch (std::exception &ex) {
+		error = ex.what();
+	} catch (...) {
+		error = "Unknown C++ exception.";
+	}
+	return error;
+}
+
 BackgroundSlicingProcess::BackgroundSlicingProcess()
 {
     boost::filesystem::path temp_path(wxStandardPaths::Get().GetTempDir().utf8_str().data());
@@ -109,19 +139,19 @@ void BackgroundSlicingProcess::process_fff()
 			switch (copy_ret_val) {
 			case SUCCESS: break; // no error
 			case FAIL_COPY_FILE:
-				throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
+				throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
 				break;
 			case FAIL_FILES_DIFFERENT: 
-				throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
+				throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
 				break;
 			case FAIL_RENAMING: 
-				throw std::runtime_error((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str()); 
+				throw Slic3r::RuntimeError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str()); 
 				break;
 			case FAIL_CHECK_ORIGIN_NOT_OPENED: 
-				throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
+				throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
 				break;
 			case FAIL_CHECK_TARGET_NOT_OPENED: 
-				throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str()); 
+				throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str()); 
 				break;
 			default:
 				BOOST_LOG_TRIVIAL(warning) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
@@ -210,7 +240,7 @@ void BackgroundSlicingProcess::thread_proc()
 		// Process the background slicing task.
 		m_state = STATE_RUNNING;
 		lck.unlock();
-		std::string error;
+		std::exception_ptr exception;
 		try {
 			assert(m_print != nullptr);
 			switch(m_print->technology()) {
@@ -221,15 +251,8 @@ void BackgroundSlicingProcess::thread_proc()
 		} catch (CanceledException & /* ex */) {
 			// Canceled, this is all right.
 			assert(m_print->canceled());
-        } catch (const std::bad_alloc& ex) {
-            wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. "
-                                  "If you are sure you have enough RAM on your system, this may also be a bug and we would "
-                                  "be glad if you reported it."))) % SLIC3R_APP_NAME).str());
-            error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
-        } catch (std::exception &ex) {
-			error = ex.what();
 		} catch (...) {
-			error = "Unknown C++ exception.";
+			exception = std::current_exception();
 		}
 		m_print->finalize();
 		lck.lock();
@@ -237,9 +260,9 @@ void BackgroundSlicingProcess::thread_proc()
 		if (m_print->cancel_status() != Print::CANCELED_INTERNAL) {
 			// Only post the canceled event, if canceled by user.
 			// Don't post the canceled event, if canceled from Print::apply().
-			wxCommandEvent evt(m_event_finished_id);
-            evt.SetString(GUI::from_u8(error));
-			evt.SetInt(m_print->canceled() ? -1 : (error.empty() ? 1 : 0));
+			SlicingProcessCompletedEvent evt(m_event_finished_id, 0, 
+				(m_state == STATE_CANCELED) ? SlicingProcessCompletedEvent::Cancelled :
+				exception ? SlicingProcessCompletedEvent::Error : SlicingProcessCompletedEvent::Finished, exception);
         	wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
         }
 	    m_print->restart();
@@ -299,7 +322,7 @@ bool BackgroundSlicingProcess::start()
 		// The background processing thread is already running.
 		return false;
 	if (! this->idle())
-		throw std::runtime_error("Cannot start a background task, the worker thread is not idle.");
+		throw Slic3r::RuntimeError("Cannot start a background task, the worker thread is not idle.");
 	m_state = STATE_STARTED;
 	m_print->set_cancel_callback([this](){ this->stop_internal(); });
 	lck.unlock();
@@ -494,7 +517,7 @@ void BackgroundSlicingProcess::prepare_upload()
 	if (m_print == m_fff_print) {
 		m_print->set_status(95, _utf8(L("Running post-processing scripts")));
 		if (copy_file(m_temp_output_path, source_path.string()) != SUCCESS) {
-			throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
+			throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
 		}
 		run_post_process_scripts(source_path.string(), m_fff_print->config());
         m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
index 9fe1157b6..1b2687e63 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
@@ -37,6 +37,36 @@ public:
 	PrintBase::SlicingStatus status;
 };
 
+class SlicingProcessCompletedEvent : public wxEvent
+{
+public:
+	enum StatusType {
+		Finished,
+		Cancelled,
+		Error
+	};
+
+	SlicingProcessCompletedEvent(wxEventType eventType, int winid, StatusType status, std::exception_ptr exception) :
+		wxEvent(winid, eventType), m_status(status), m_exception(exception) {}
+	virtual wxEvent* Clone() const { return new SlicingProcessCompletedEvent(*this); }
+
+	StatusType 	status()    const { return m_status; }
+	bool 		finished()  const { return m_status == Finished; }
+	bool 		success()   const { return m_status == Finished; }
+	bool 		cancelled() const { return m_status == Cancelled; }
+	bool		error() 	const { return m_status == Error; }
+	// Unhandled error produced by stdlib or a Win32 structured exception, or unhandled Slic3r's own critical exception.
+	bool 		critical_error() const;
+	// Only valid if error()
+	void 		rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
+	// Produce a human readable message to be displayed by a notification or a message box.
+	std::string format_error_message() const;
+
+private:
+	StatusType 			m_status;
+	std::exception_ptr 	m_exception;
+};
+
 wxDEFINE_EVENT(EVT_SLICING_UPDATE, SlicingStatusEvent);
 
 // Print step IDs for keeping track of the print state.
diff --git a/src/slic3r/GUI/ConfigExceptions.hpp b/src/slic3r/GUI/ConfigExceptions.hpp
index 9038d3445..181442d4e 100644
--- a/src/slic3r/GUI/ConfigExceptions.hpp
+++ b/src/slic3r/GUI/ConfigExceptions.hpp
@@ -1,15 +1,15 @@
 #include <exception> 
 namespace Slic3r {
 
-class ConfigError : public std::runtime_error { 
-using std::runtime_error::runtime_error;
+class ConfigError : public Slic3r::RuntimeError { 
+	using Slic3r::RuntimeError::RuntimeError;
 };
 
 namespace GUI {
 
 class ConfigGUITypeError : public ConfigError { 
-using ConfigError::ConfigError;
+	using ConfigError::ConfigError;
 };
-}
 
-}
+} // namespace GUI
+} // namespace Slic3r
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index 2cedbfdf7..c98b736b7 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -123,7 +123,7 @@ Bundle& BundleMap::prusa_bundle()
 {
     auto it = find(PresetBundle::PRUSA_BUNDLE);
     if (it == end()) {
-        throw std::runtime_error("ConfigWizard: Internal error in BundleMap: PRUSA_BUNDLE not loaded");
+        throw Slic3r::RuntimeError("ConfigWizard: Internal error in BundleMap: PRUSA_BUNDLE not loaded");
     }
 
     return it->second;
diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp
index fe7ff4e5d..5441c84ed 100644
--- a/src/slic3r/GUI/FirmwareDialog.cpp
+++ b/src/slic3r/GUI/FirmwareDialog.cpp
@@ -766,7 +766,7 @@ const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) {
 			return "Original Prusa CW1";
 		break;
 
-		default: throw std::runtime_error((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str());
+		default: throw Slic3r::RuntimeError((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str());
 	}
 }
 
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index d59a83e87..40c8f96e5 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -571,7 +571,7 @@ void GUI_App::init_app_config()
         std::string error = app_config->load();
         if (!error.empty())
             // Error while parsing config file. We'll customize the error message and rethrow to be displayed.
-            throw std::runtime_error(
+            throw Slic3r::RuntimeError(
                 _u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
                     "Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
                 "\n\n" + AppConfig::config_path() + "\n\n" + error);
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 0fecc822d..f9a23cb51 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -927,7 +927,7 @@ void ImGuiWrapper::init_font(bool compress)
     if (font == nullptr) {
         font = io.Fonts->AddFontDefault();
         if (font == nullptr) {
-            throw std::runtime_error("ImGui: Could not load deafult font");
+            throw Slic3r::RuntimeError("ImGui: Could not load deafult font");
         }
     }
 
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index dd00b3d68..14defd9a9 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -7,6 +7,7 @@
 #include <wx/numformatter.h>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/classification.hpp>
+#include "libslic3r/Exception.hpp"
 #include "libslic3r/Utils.hpp"
 #include "I18N.hpp"
 
@@ -64,7 +65,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
 				break;
             case coNone:   break;
             default:
-				throw /*//!ConfigGUITypeError("")*/std::logic_error("This control doesn't exist till now"); break;
+				throw Slic3r::LogicError("This control doesn't exist till now"); break;
         }
     }
     // Grab a reference to fields for convenience
@@ -620,7 +621,7 @@ boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_
 		// Aggregate the strings the old way.
 		// Currently used for the post_process config value only.
 		if (opt_index != -1)
-			throw std::out_of_range("Can't deserialize option indexed value");
+			throw Slic3r::OutOfRange("Can't deserialize option indexed value");
 // 		return join(';', m_config->get(opt_key)});
 		return get_config_value(*m_config, opt_key);
 	}
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index f7fd608ba..6d856960d 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -107,7 +107,7 @@ namespace GUI {
 wxDEFINE_EVENT(EVT_SCHEDULE_BACKGROUND_PROCESS,     SimpleEvent);
 wxDEFINE_EVENT(EVT_SLICING_UPDATE,                  SlicingStatusEvent);
 wxDEFINE_EVENT(EVT_SLICING_COMPLETED,               wxCommandEvent);
-wxDEFINE_EVENT(EVT_PROCESS_COMPLETED,               wxCommandEvent);
+wxDEFINE_EVENT(EVT_PROCESS_COMPLETED,               SlicingProcessCompletedEvent);
 wxDEFINE_EVENT(EVT_EXPORT_BEGAN,                    wxCommandEvent);
 
 // Sidebar widgets
@@ -1682,7 +1682,7 @@ struct Plater::priv
     void on_select_preset(wxCommandEvent&);
     void on_slicing_update(SlicingStatusEvent&);
     void on_slicing_completed(wxCommandEvent&);
-    void on_process_completed(wxCommandEvent&);
+    void on_process_completed(SlicingProcessCompletedEvent&);
 	void on_export_began(wxCommandEvent&);
     void on_layer_editing_toggled(bool enable);
 	void on_slicing_began();
@@ -3510,7 +3510,7 @@ bool Plater::priv::warnings_dialog()
 	return res == wxID_OK;
 
 }
-void Plater::priv::on_process_completed(wxCommandEvent &evt)
+void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
 {
     // Stop the background task, wait until the thread goes into the "Idle" state.
     // At this point of time the thread should be either finished or canceled,
@@ -3519,27 +3519,23 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
     this->statusbar()->reset_cancel_callback();
     this->statusbar()->stop_busy();
 
-    const bool canceled = evt.GetInt() < 0;
-    const bool error = evt.GetInt() == 0;
-    const bool success  = evt.GetInt() > 0;
     // Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
     this->background_process.reset_export();
 
-    if (error) {
-        wxString message = evt.GetString();
-        if (message.IsEmpty())
-            message = _L("Export failed.");
-		notification_manager->push_slicing_error_notification(boost::nowide::narrow(message), *q->get_current_canvas3D());
-        this->statusbar()->set_status_text(message);
+    if (evt.error()) {
+        std::string message = evt.format_error_message();
+        //FIXME show a messagebox if evt.critical_error().
+		notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D());
+        this->statusbar()->set_status_text(from_u8(message));
 		const wxString invalid_str = _L("Invalid data");
 		for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
 			sidebar->set_btn_label(btn, invalid_str);
 		process_completed_with_error = true;
     }
-    if (canceled)
+    if (evt.cancelled())
         this->statusbar()->set_status_text(_L("Cancelled"));
 
-    this->sidebar->show_sliced_info_sizer(success);
+    this->sidebar->show_sliced_info_sizer(evt.success());
 
     // This updates the "Slice now", "Export G-code", "Arrange" buttons status.
     // Namely, it refreshes the "Out of print bed" property of all the ModelObjects, and it enables
@@ -3560,7 +3556,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
     default: break;
     }
 	
-    if (canceled) {
+    if (evt.cancelled()) {
         if (wxGetApp().get_mode() == comSimple)
             sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now");
         show_action_buttons(true);
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index d23c3415f..6f79db591 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -436,7 +436,7 @@ wxBitmap create_scaled_bitmap(  const std::string& bmp_name_in,
 
     if (bmp == nullptr) {
         // Neither SVG nor PNG has been found, raise error
-        throw std::runtime_error("Could not load bitmap: " + bmp_name);
+        throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
     }
 
     return *bmp;
diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp
index 86ff79aaa..bcab6daaf 100644
--- a/src/slic3r/Utils/FixModelByWin10.cpp
+++ b/src/slic3r/Utils/FixModelByWin10.cpp
@@ -209,10 +209,10 @@ typedef std::function<void (const char * /* message */, unsigned /* progress */)
 void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel)
 {
 	if (! is_windows10())
-		throw std::runtime_error("fix_model_by_win10_sdk called on non Windows 10 system");
+		throw Slic3r::RuntimeError("fix_model_by_win10_sdk called on non Windows 10 system");
 
 	if (! winrt_load_runtime_object_library())
-		throw std::runtime_error("Failed to initialize the WinRT library.");
+		throw Slic3r::RuntimeError("Failed to initialize the WinRT library.");
 
 	HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
 	{
@@ -232,7 +232,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		if (status == AsyncStatus::Completed)
 			hr = modelAsync->GetResults(model.GetAddressOf());
 		else
-			throw std::runtime_error(L("Failed loading the input model."));
+			throw Slic3r::RuntimeError(L("Failed loading the input model."));
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
 		hr = model->get_Meshes(meshes.GetAddressOf());
@@ -245,7 +245,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		hr = model->RepairAsync(repairAsync.GetAddressOf());
 		status = winrt_async_await(repairAsync, throw_on_cancel);
 		if (status != AsyncStatus::Completed)
-			throw std::runtime_error(L("Mesh repair failed."));
+			throw Slic3r::RuntimeError(L("Mesh repair failed."));
 		repairAsync->GetResults();
 
 		on_progress(L("Loading repaired model"), 60);
@@ -260,14 +260,14 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 		hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
 		status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
 		if (status != AsyncStatus::Completed)
-			throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
+			throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
 		hr = saveToPackageAsync->GetResults();
 
 		Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
 		hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
 		status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
 		if (status != AsyncStatus::Completed)
-			throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
+			throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
 		Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
 		hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
 
@@ -299,7 +299,7 @@ void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path
 			hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
 			status = winrt_async_await(asyncRead, throw_on_cancel);
 			if (status != AsyncStatus::Completed)
-				throw std::runtime_error(L("Saving mesh into the 3MF container failed."));
+				throw Slic3r::RuntimeError(L("Saving mesh into the 3MF container failed."));
 			hr = buffer->get_Length(&length);
 			if (length == 0)
 				break;
@@ -365,7 +365,7 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
 				model_object->add_instance();
 				if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false)) {
 					boost::filesystem::remove(path_src);
-					throw std::runtime_error(L("Export of a temporary 3mf file failed"));
+					throw Slic3r::RuntimeError(L("Export of a temporary 3mf file failed"));
 				}
 				model.clear_objects();
 				model.clear_materials();
@@ -380,15 +380,15 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
 				bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config, &model, false);
 			    boost::filesystem::remove(path_dst);
 				if (! loaded)
-	 				throw std::runtime_error(L("Import of the repaired 3mf file failed"));
+	 				throw Slic3r::RuntimeError(L("Import of the repaired 3mf file failed"));
 	 			if (model.objects.size() == 0)
-	 				throw std::runtime_error(L("Repaired 3MF file does not contain any object"));
+	 				throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any object"));
 	 			if (model.objects.size() > 1)
-	 				throw std::runtime_error(L("Repaired 3MF file contains more than one object"));
+	 				throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one object"));
 	 			if (model.objects.front()->volumes.size() == 0)
-	 				throw std::runtime_error(L("Repaired 3MF file does not contain any volume"));
+	 				throw Slic3r::RuntimeError(L("Repaired 3MF file does not contain any volume"));
 				if (model.objects.front()->volumes.size() > 1)
-	 				throw std::runtime_error(L("Repaired 3MF file contains more than one volume"));
+	 				throw Slic3r::RuntimeError(L("Repaired 3MF file contains more than one volume"));
 	 			meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
 			}
 			for (size_t i = 0; i < volumes.size(); ++ i) {
diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp
index e55c21fe1..8c79a478a 100644
--- a/src/slic3r/Utils/Http.cpp
+++ b/src/slic3r/Utils/Http.cpp
@@ -156,7 +156,7 @@ Http::priv::priv(const std::string &url)
     Http::tls_global_init();
     
 	if (curl == nullptr) {
-		throw std::runtime_error(std::string("Could not construct Curl object"));
+		throw Slic3r::RuntimeError(std::string("Could not construct Curl object"));
 	}
 
 	set_timeout_connect(DEFAULT_TIMEOUT_CONNECT);
diff --git a/src/slic3r/Utils/Serial.cpp b/src/slic3r/Utils/Serial.cpp
index 737e76c0b..959c60c37 100644
--- a/src/slic3r/Utils/Serial.cpp
+++ b/src/slic3r/Utils/Serial.cpp
@@ -298,7 +298,7 @@ void Serial::set_baud_rate(unsigned baud_rate)
 
 		auto handle_errno = [](int retval) {
 			if (retval != 0) {
-				throw std::runtime_error(
+				throw Slic3r::RuntimeError(
 					(boost::format("Could not set baud rate: %1%") % strerror(errno)).str()
 				);
 			}
@@ -346,7 +346,7 @@ void Serial::set_baud_rate(unsigned baud_rate)
 		handle_errno(::cfsetspeed(&ios, baud_rate));
 		handle_errno(::tcsetattr(handle, TCSAFLUSH, &ios));
 #else
-		throw std::runtime_error("Custom baud rates are not currently supported on this OS");
+		throw Slic3r::RuntimeError("Custom baud rates are not currently supported on this OS");
 #endif
 	}
 }
@@ -358,7 +358,7 @@ void Serial::set_DTR(bool on)
 	auto handle = native_handle();
 #if defined(_WIN32) && !defined(__SYMBIAN32__)
 	if (! EscapeCommFunction(handle, on ? SETDTR : CLRDTR)) {
-		throw std::runtime_error("Could not set serial port DTR");
+		throw Slic3r::RuntimeError("Could not set serial port DTR");
 	}
 #else
 	int status;
@@ -369,7 +369,7 @@ void Serial::set_DTR(bool on)
 		}
 	}
 
-	throw std::runtime_error(
+	throw Slic3r::RuntimeError(
 		(boost::format("Could not set serial port DTR: %1%") % strerror(errno)).str()
 	);
 #endif
diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp
index 9c8d7a8c6..10b8062f7 100644
--- a/src/slic3r/Utils/UndoRedo.cpp
+++ b/src/slic3r/Utils/UndoRedo.cpp
@@ -847,7 +847,7 @@ void StackImpl::load_snapshot(size_t timestamp, Slic3r::Model& model, Slic3r::GU
 	// Find the snapshot by time. It must exist.
 	const auto it_snapshot = std::lower_bound(m_snapshots.begin(), m_snapshots.end(), Snapshot(timestamp));
 	if (it_snapshot == m_snapshots.end() || it_snapshot->timestamp != timestamp)
-		throw std::runtime_error((boost::format("Snapshot with timestamp %1% does not exist") % timestamp).str());
+		throw Slic3r::RuntimeError((boost::format("Snapshot with timestamp %1% does not exist") % timestamp).str());
 
 	m_active_snapshot_time = timestamp;
 	model.clear_objects();
diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp
index 09ca730ec..8e5f6bafd 100644
--- a/tests/fff_print/test_data.cpp
+++ b/tests/fff_print/test_data.cpp
@@ -137,7 +137,7 @@ TriangleMesh mesh(TestMesh m)
             	{ {0,1,2}, {2,1,3}, {4,0,5}, {4,1,0}, {6,4,7}, {7,4,5}, {4,8,1}, {0,2,5}, {5,2,9}, {2,10,9}, {10,3,11}, {2,3,10}, {9,10,12}, {13,9,12}, {3,1,8}, {11,3,8}, {10,11,8}, {4,10,8}, {6,12,10}, {4,6,10}, {7,13,12}, {6,7,12}, {7,5,9}, {13,7,9} });
             break;
         default:
-        	throw std::invalid_argument("Slic3r::Test::mesh(): called with invalid mesh ID");
+        	throw Slic3r::InvalidArgument("Slic3r::Test::mesh(): called with invalid mesh ID");
             break;        
     }