diff --git a/.travis.yml b/.travis.yml
index 6bf2297e..ef5c6143 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -71,6 +71,21 @@ matrix:
     after_success:
       - make cppcheck
 
+  # no exceptions
+
+  - os: linux
+    compiler: gcc
+    env:
+      - COMPILER=g++-4.9
+      - SPECIAL=no_exceptions
+      - TEST_PATTERN=-e \"*\"
+    addons:
+      apt:
+        sources: ['ubuntu-toolchain-r-test']
+        packages: [g++-4.9, cppcheck]
+    before_script:
+      - CPPFLAGS="-DJSON_NOEXCEPTION" make
+
   # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
 
   - os: linux
diff --git a/src/json.hpp b/src/json.hpp
index 3200e095..fa9b85f2 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -88,6 +88,17 @@ SOFTWARE.
     #define JSON_DEPRECATED
 #endif
 
+// allow to disable exceptions
+#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+#else
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+#endif
+
 /*!
 @brief namespace for Niels Lohmann
 @see https://github.com/nlohmann
@@ -945,7 +956,7 @@ class basic_json
                 {
                     if (t == value_t::null)
                     {
-                        throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE
+                        JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10")); // LCOV_EXCL_LINE
                     }
                     break;
                 }
@@ -1717,7 +1728,7 @@ class basic_json
             // if object is wanted but impossible, throw an exception
             if (manual_type == value_t::object and not is_an_object)
             {
-                throw std::domain_error("cannot create object from initializer list");
+                JSON_THROW(std::domain_error("cannot create object from initializer list"));
             }
         }
 
@@ -1895,7 +1906,7 @@ class basic_json
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
         {
-            throw std::domain_error("iterators are not compatible");
+            JSON_THROW(std::domain_error("iterators are not compatible"));
         }
 
         // copy type from first iterator
@@ -1912,7 +1923,7 @@ class basic_json
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
                 {
-                    throw std::out_of_range("iterators out of range");
+                    JSON_THROW(std::out_of_range("iterators out of range"));
                 }
                 break;
             }
@@ -1971,7 +1982,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
+                JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()));
             }
         }
 
@@ -2655,7 +2666,7 @@ class basic_json
             return T(m_value.object->begin(), m_value.object->end());
         }
 
-        throw std::domain_error("type must be object, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
     }
 
     /// get an object (explicit)
@@ -2666,7 +2677,7 @@ class basic_json
             return *(m_value.object);
         }
 
-        throw std::domain_error("type must be object, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2689,7 +2700,7 @@ class basic_json
             return to_vector;
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2710,7 +2721,7 @@ class basic_json
             return to_vector;
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2724,7 +2735,7 @@ class basic_json
             return T(m_value.array->begin(), m_value.array->end());
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2735,7 +2746,7 @@ class basic_json
             return *(m_value.array);
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get a string (explicit)
@@ -2748,7 +2759,7 @@ class basic_json
             return *m_value.string;
         }
 
-        throw std::domain_error("type must be string, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be string, but is " + type_name()));
     }
 
     /// get a number (explicit)
@@ -2775,17 +2786,22 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("type must be number, but is " + type_name());
+                JSON_THROW(std::domain_error("type must be number, but is " + type_name()));
             }
         }
     }
 
     /// get a boolean (explicit)
-    constexpr boolean_t get_impl(boolean_t* /*unused*/) const
+    boolean_t get_impl(boolean_t* /*unused*/) const
     {
-        return is_boolean()
-               ? m_value.boolean
-               : throw std::domain_error("type must be boolean, but is " + type_name());
+        if (is_boolean())
+        {
+            return m_value.boolean;
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("type must be boolean, but is " + type_name()));
+        }
     }
 
     /// get a pointer to the value (object)
@@ -3197,19 +3213,19 @@ class basic_json
         // at only works for arrays
         if (is_array())
         {
-            try
+            JSON_TRY
             {
                 return m_value.array->at(idx);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3240,19 +3256,19 @@ class basic_json
         // at only works for arrays
         if (is_array())
         {
-            try
+            JSON_TRY
             {
                 return m_value.array->at(idx);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3287,19 +3303,19 @@ class basic_json
         // at only works for objects
         if (is_object())
         {
-            try
+            JSON_TRY
             {
                 return m_value.object->at(key);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("key '" + key + "' not found");
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3334,19 +3350,19 @@ class basic_json
         // at only works for objects
         if (is_object())
         {
-            try
+            JSON_TRY
             {
                 return m_value.object->at(key);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("key '" + key + "' not found");
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3399,7 +3415,7 @@ class basic_json
             return m_value.array->operator[](idx);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3429,7 +3445,7 @@ class basic_json
             return m_value.array->operator[](idx);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3475,7 +3491,7 @@ class basic_json
             return m_value.object->operator[](key);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3517,7 +3533,7 @@ class basic_json
             return m_value.object->find(key)->second;
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3632,7 +3648,7 @@ class basic_json
             return m_value.object->operator[](key);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3675,7 +3691,7 @@ class basic_json
             return m_value.object->find(key)->second;
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3744,7 +3760,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use value() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
         }
     }
 
@@ -3806,17 +3822,17 @@ class basic_json
         if (is_object())
         {
             // if pointer resolves a value, return it or use default value
-            try
+            JSON_TRY
             {
                 return ptr.get_checked(this);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 return default_value;
             }
         }
 
-        throw std::domain_error("cannot use value() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
     }
 
     /*!
@@ -3967,7 +3983,7 @@ class basic_json
         // make sure iterator fits the current value
         if (this != pos.m_object)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         IteratorType result = end();
@@ -3982,7 +3998,7 @@ class basic_json
             {
                 if (not pos.m_it.primitive_iterator.is_begin())
                 {
-                    throw std::out_of_range("iterator out of range");
+                    JSON_THROW(std::out_of_range("iterator out of range"));
                 }
 
                 if (is_string())
@@ -4012,7 +4028,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use erase() with " + type_name());
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
             }
         }
 
@@ -4074,7 +4090,7 @@ class basic_json
         // make sure iterator fits the current value
         if (this != first.m_object or this != last.m_object)
         {
-            throw std::domain_error("iterators do not fit current value");
+            JSON_THROW(std::domain_error("iterators do not fit current value"));
         }
 
         IteratorType result = end();
@@ -4089,7 +4105,7 @@ class basic_json
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
                 {
-                    throw std::out_of_range("iterators out of range");
+                    JSON_THROW(std::out_of_range("iterators out of range"));
                 }
 
                 if (is_string())
@@ -4121,7 +4137,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use erase() with " + type_name());
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
             }
         }
 
@@ -4165,7 +4181,7 @@ class basic_json
             return m_value.object->erase(key);
         }
 
-        throw std::domain_error("cannot use erase() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
     }
 
     /*!
@@ -4199,14 +4215,14 @@ class basic_json
         {
             if (idx >= size())
             {
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
 
             m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
         }
         else
         {
-            throw std::domain_error("cannot use erase() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
         }
     }
 
@@ -4924,7 +4940,7 @@ class basic_json
         // push_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -4960,7 +4976,7 @@ class basic_json
         // push_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -5010,7 +5026,7 @@ class basic_json
         // push_back only works for null objects or objects
         if (not(is_null() or is_object()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an object
@@ -5110,7 +5126,7 @@ class basic_json
         // emplace_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use emplace_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -5158,7 +5174,7 @@ class basic_json
         // emplace only works for null objects or arrays
         if (not(is_null() or is_object()))
         {
-            throw std::domain_error("cannot use emplace() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use emplace() with " + type_name()));
         }
 
         // transform null object into an object
@@ -5209,7 +5225,7 @@ class basic_json
             // check if iterator pos fits to this JSON value
             if (pos.m_object != this)
             {
-                throw std::domain_error("iterator does not fit current value");
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
             }
 
             // insert to array and return iterator
@@ -5218,7 +5234,7 @@ class basic_json
             return result;
         }
 
-        throw std::domain_error("cannot use insert() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
     }
 
     /*!
@@ -5262,7 +5278,7 @@ class basic_json
             // check if iterator pos fits to this JSON value
             if (pos.m_object != this)
             {
-                throw std::domain_error("iterator does not fit current value");
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
             }
 
             // insert to array and return iterator
@@ -5271,7 +5287,7 @@ class basic_json
             return result;
         }
 
-        throw std::domain_error("cannot use insert() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
     }
 
     /*!
@@ -5309,24 +5325,24 @@ class basic_json
         // insert only works for arrays
         if (not is_array())
         {
-            throw std::domain_error("cannot use insert() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
         }
 
         // check if iterator pos fits to this JSON value
         if (pos.m_object != this)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         // check if range iterators belong to the same JSON object
         if (first.m_object != last.m_object)
         {
-            throw std::domain_error("iterators do not fit");
+            JSON_THROW(std::domain_error("iterators do not fit"));
         }
 
         if (first.m_object == this or last.m_object == this)
         {
-            throw std::domain_error("passed iterators may not belong to container");
+            JSON_THROW(std::domain_error("passed iterators may not belong to container"));
         }
 
         // insert to array and return iterator
@@ -5367,13 +5383,13 @@ class basic_json
         // insert only works for arrays
         if (not is_array())
         {
-            throw std::domain_error("cannot use insert() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
         }
 
         // check if iterator pos fits to this JSON value
         if (pos.m_object != this)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         // insert to array and return iterator
@@ -5440,7 +5456,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -5473,7 +5489,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -5506,7 +5522,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -6350,7 +6366,7 @@ class basic_json
     {
         if (current_index + sizeof(T) + 1 > vec.size())
         {
-            throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector");
+            JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"));
         }
 
         T result;
@@ -6900,19 +6916,19 @@ class basic_json
         // simple case: requested length is greater than the vector's length
         if (len > size or offset > size)
         {
-            throw std::out_of_range("len out of range");
+            JSON_THROW(std::out_of_range("len out of range"));
         }
 
         // second case: adding offset would result in overflow
         if ((size > (std::numeric_limits<size_t>::max() - offset)))
         {
-            throw std::out_of_range("len+offset out of range");
+            JSON_THROW(std::out_of_range("len+offset out of range"));
         }
 
         // last case: reading past the end of the vector
         if (len + offset > size)
         {
-            throw std::out_of_range("len+offset out of range");
+            JSON_THROW(std::out_of_range("len+offset out of range"));
         }
     }
 
@@ -7148,7 +7164,7 @@ class basic_json
 
                 default:
                 {
-                    throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+                    JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
                 }
             }
         }
@@ -7631,7 +7647,7 @@ class basic_json
 
             default: // anything else (0xFF is handled inside the other types)
             {
-                throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+                JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
             }
         }
     }
@@ -8521,7 +8537,7 @@ class basic_json
 
                 case basic_json::value_t::null:
                 {
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
 
                 default:
@@ -8531,7 +8547,7 @@ class basic_json
                         return *m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8565,7 +8581,7 @@ class basic_json
                         return m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8665,7 +8681,7 @@ class basic_json
             // if objects are not the same, the comparison is undefined
             if (m_object != other.m_object)
             {
-                throw std::domain_error("cannot compare iterators of different containers");
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
             }
 
             assert(m_object != nullptr);
@@ -8707,7 +8723,7 @@ class basic_json
             // if objects are not the same, the comparison is undefined
             if (m_object != other.m_object)
             {
-                throw std::domain_error("cannot compare iterators of different containers");
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
             }
 
             assert(m_object != nullptr);
@@ -8716,7 +8732,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot compare order of object iterators");
+                    JSON_THROW(std::domain_error("cannot compare order of object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8770,7 +8786,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use offsets with object iterators");
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8832,7 +8848,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use offsets with object iterators");
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8859,7 +8875,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use operator[] for object iterators");
+                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8869,7 +8885,7 @@ class basic_json
 
                 case basic_json::value_t::null:
                 {
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
 
                 default:
@@ -8879,7 +8895,7 @@ class basic_json
                         return *m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8897,7 +8913,7 @@ class basic_json
                 return m_it.object_iterator->first;
             }
 
-            throw std::domain_error("cannot use key() for non-object iterators");
+            JSON_THROW(std::domain_error("cannot use key() for non-object iterators"));
         }
 
         /*!
@@ -9082,7 +9098,7 @@ class basic_json
             // immediately abort if stream is erroneous
             if (s.fail())
             {
-                throw std::invalid_argument("stream error");
+                JSON_THROW(std::invalid_argument("stream error"));
             }
 
             // fill buffer
@@ -9149,7 +9165,7 @@ class basic_json
                 }
                 else
                 {
-                    throw std::invalid_argument("missing or wrong low surrogate");
+                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
                 }
             }
 
@@ -9183,7 +9199,7 @@ class basic_json
             }
             else
             {
-                throw std::out_of_range("code points above 0x10FFFF are invalid");
+                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
             }
 
             return result;
@@ -10415,7 +10431,7 @@ basic_json_parser_66:
                                 // make sure there is a subsequent unicode
                                 if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
                                 {
-                                    throw std::invalid_argument("missing low surrogate");
+                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
                                 }
 
                                 // get code yyyy from uxxxx\uyyyy
@@ -10428,7 +10444,7 @@ basic_json_parser_66:
                             else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
                             {
                                 // we found a lone low surrogate
-                                throw std::invalid_argument("missing high surrogate");
+                                JSON_THROW(std::invalid_argument("missing high surrogate"));
                             }
                             else
                             {
@@ -10906,7 +10922,7 @@ basic_json_parser_66:
                               "'") :
                               lexer::token_type_name(last_token));
                 error_msg += "; expected " + lexer::token_type_name(t);
-                throw std::invalid_argument(error_msg);
+                JSON_THROW(std::invalid_argument(error_msg));
             }
         }
 
@@ -10918,7 +10934,7 @@ basic_json_parser_66:
                 error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
                               "'") :
                               lexer::token_type_name(last_token));
-                throw std::invalid_argument(error_msg);
+                JSON_THROW(std::invalid_argument(error_msg));
             }
         }
 
@@ -11014,7 +11030,7 @@ basic_json_parser_66:
         {
             if (is_root())
             {
-                throw std::domain_error("JSON pointer has no parent");
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
             }
 
             auto last = reference_tokens.back();
@@ -11032,7 +11048,7 @@ basic_json_parser_66:
         {
             if (is_root())
             {
-                throw std::domain_error("JSON pointer has no parent");
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
             }
 
             json_pointer result = *this;
@@ -11093,7 +11109,7 @@ basic_json_parser_66:
                     */
                     default:
                     {
-                        throw std::domain_error("invalid value to unflatten");
+                        JSON_THROW(std::domain_error("invalid value to unflatten"));
                     }
                 }
             }
@@ -11161,7 +11177,7 @@ basic_json_parser_66:
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         if (reference_token == "-")
@@ -11179,7 +11195,7 @@ basic_json_parser_66:
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -11213,7 +11229,7 @@ basic_json_parser_66:
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // note: at performs range check
@@ -11223,7 +11239,7 @@ basic_json_parser_66:
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -11265,7 +11281,7 @@ basic_json_parser_66:
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // use unchecked array access
@@ -11275,7 +11291,7 @@ basic_json_parser_66:
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -11309,7 +11325,7 @@ basic_json_parser_66:
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // note: at performs range check
@@ -11319,7 +11335,7 @@ basic_json_parser_66:
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -11341,7 +11357,7 @@ basic_json_parser_66:
             // check if nonempty reference string begins with slash
             if (reference_string[0] != '/')
             {
-                throw std::domain_error("JSON pointer must be empty or begin with '/'");
+                JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'"));
             }
 
             // extract the reference tokens:
@@ -11376,7 +11392,7 @@ basic_json_parser_66:
                             (reference_token[pos + 1] != '0' and
                              reference_token[pos + 1] != '1'))
                     {
-                        throw std::domain_error("escape error: '~' must be followed with '0' or '1'");
+                        JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'"));
                     }
                 }
 
@@ -11502,7 +11518,7 @@ basic_json_parser_66:
         {
             if (not value.is_object())
             {
-                throw std::domain_error("only objects can be unflattened");
+                JSON_THROW(std::domain_error("only objects can be unflattened"));
             }
 
             basic_json result;
@@ -11512,7 +11528,7 @@ basic_json_parser_66:
             {
                 if (not element.second.is_primitive())
                 {
-                    throw std::domain_error("values in object must be primitive");
+                    JSON_THROW(std::domain_error("values in object must be primitive"));
                 }
 
                 // assign value to reference pointed to by JSON pointer; Note
@@ -11841,7 +11857,7 @@ basic_json_parser_66:
                             if (static_cast<size_type>(idx) > parent.size())
                             {
                                 // avoid undefined behavior
-                                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
                             }
                             else
                             {
@@ -11879,7 +11895,7 @@ basic_json_parser_66:
                 }
                 else
                 {
-                    throw std::out_of_range("key '" + last_path + "' not found");
+                    JSON_THROW(std::out_of_range("key '" + last_path + "' not found"));
                 }
             }
             else if (parent.is_array())
@@ -11893,7 +11909,7 @@ basic_json_parser_66:
         if (not json_patch.is_array())
         {
             // a JSON patch must be an array of objects
-            throw std::invalid_argument("JSON patch must be an array of objects");
+            JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
         }
 
         // iterate and apply th eoperations
@@ -11913,13 +11929,13 @@ basic_json_parser_66:
                 // check if desired value is present
                 if (it == val.m_value.object->end())
                 {
-                    throw std::invalid_argument(error_msg + " must have member '" + member + "'");
+                    JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'"));
                 }
 
                 // check if result is of type string
                 if (string_type and not it->second.is_string())
                 {
-                    throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
+                    JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'"));
                 }
 
                 // no error: return value
@@ -11929,7 +11945,7 @@ basic_json_parser_66:
             // type check
             if (not val.is_object())
             {
-                throw std::invalid_argument("JSON patch must be an array of objects");
+                JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
             }
 
             // collect mandatory members
@@ -11988,13 +12004,13 @@ basic_json_parser_66:
                 case patch_operations::test:
                 {
                     bool success = false;
-                    try
+                    JSON_TRY
                     {
                         // check if "value" matches the one at "path"
                         // the "path" location must exist - use at()
                         success = (result.at(ptr) == get_value("test", "value", false));
                     }
-                    catch (std::out_of_range&)
+                    JSON_CATCH (std::out_of_range&)
                     {
                         // ignore out of range errors: success remains false
                     }
@@ -12002,7 +12018,7 @@ basic_json_parser_66:
                     // throw an exception if test fails
                     if (not success)
                     {
-                        throw std::domain_error("unsuccessful: " + val.dump());
+                        JSON_THROW(std::domain_error("unsuccessful: " + val.dump()));
                     }
 
                     break;
@@ -12012,7 +12028,7 @@ basic_json_parser_66:
                 {
                     // op must be "add", "remove", "replace", "move", "copy", or
                     // "test"
-                    throw std::invalid_argument("operation value '" + op + "' is invalid");
+                    JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid"));
                 }
             }
         }
@@ -12285,4 +12301,10 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
     #pragma GCC diagnostic pop
 #endif
 
+// clean up
+#undef JSON_THROW
+#undef JSON_TRY
+#undef JSON_CATCH
+#undef JSON_DEPRECATED
+
 #endif
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index c7171a27..886b9dde 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -88,6 +88,17 @@ SOFTWARE.
     #define JSON_DEPRECATED
 #endif
 
+// allow to disable exceptions
+#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+#else
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+#endif
+
 /*!
 @brief namespace for Niels Lohmann
 @see https://github.com/nlohmann
@@ -945,7 +956,7 @@ class basic_json
                 {
                     if (t == value_t::null)
                     {
-                        throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE
+                        JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10")); // LCOV_EXCL_LINE
                     }
                     break;
                 }
@@ -1717,7 +1728,7 @@ class basic_json
             // if object is wanted but impossible, throw an exception
             if (manual_type == value_t::object and not is_an_object)
             {
-                throw std::domain_error("cannot create object from initializer list");
+                JSON_THROW(std::domain_error("cannot create object from initializer list"));
             }
         }
 
@@ -1895,7 +1906,7 @@ class basic_json
         // make sure iterator fits the current value
         if (first.m_object != last.m_object)
         {
-            throw std::domain_error("iterators are not compatible");
+            JSON_THROW(std::domain_error("iterators are not compatible"));
         }
 
         // copy type from first iterator
@@ -1912,7 +1923,7 @@ class basic_json
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
                 {
-                    throw std::out_of_range("iterators out of range");
+                    JSON_THROW(std::out_of_range("iterators out of range"));
                 }
                 break;
             }
@@ -1971,7 +1982,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
+                JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()));
             }
         }
 
@@ -2655,7 +2666,7 @@ class basic_json
             return T(m_value.object->begin(), m_value.object->end());
         }
 
-        throw std::domain_error("type must be object, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
     }
 
     /// get an object (explicit)
@@ -2666,7 +2677,7 @@ class basic_json
             return *(m_value.object);
         }
 
-        throw std::domain_error("type must be object, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2689,7 +2700,7 @@ class basic_json
             return to_vector;
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2710,7 +2721,7 @@ class basic_json
             return to_vector;
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2724,7 +2735,7 @@ class basic_json
             return T(m_value.array->begin(), m_value.array->end());
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get an array (explicit)
@@ -2735,7 +2746,7 @@ class basic_json
             return *(m_value.array);
         }
 
-        throw std::domain_error("type must be array, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
     }
 
     /// get a string (explicit)
@@ -2748,7 +2759,7 @@ class basic_json
             return *m_value.string;
         }
 
-        throw std::domain_error("type must be string, but is " + type_name());
+        JSON_THROW(std::domain_error("type must be string, but is " + type_name()));
     }
 
     /// get a number (explicit)
@@ -2775,17 +2786,22 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("type must be number, but is " + type_name());
+                JSON_THROW(std::domain_error("type must be number, but is " + type_name()));
             }
         }
     }
 
     /// get a boolean (explicit)
-    constexpr boolean_t get_impl(boolean_t* /*unused*/) const
+    boolean_t get_impl(boolean_t* /*unused*/) const
     {
-        return is_boolean()
-               ? m_value.boolean
-               : throw std::domain_error("type must be boolean, but is " + type_name());
+        if (is_boolean())
+        {
+            return m_value.boolean;
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("type must be boolean, but is " + type_name()));
+        }
     }
 
     /// get a pointer to the value (object)
@@ -3197,19 +3213,19 @@ class basic_json
         // at only works for arrays
         if (is_array())
         {
-            try
+            JSON_TRY
             {
                 return m_value.array->at(idx);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3240,19 +3256,19 @@ class basic_json
         // at only works for arrays
         if (is_array())
         {
-            try
+            JSON_TRY
             {
                 return m_value.array->at(idx);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3287,19 +3303,19 @@ class basic_json
         // at only works for objects
         if (is_object())
         {
-            try
+            JSON_TRY
             {
                 return m_value.object->at(key);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("key '" + key + "' not found");
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3334,19 +3350,19 @@ class basic_json
         // at only works for objects
         if (is_object())
         {
-            try
+            JSON_TRY
             {
                 return m_value.object->at(key);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 // create better exception explanation
-                throw std::out_of_range("key '" + key + "' not found");
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
             }
         }
         else
         {
-            throw std::domain_error("cannot use at() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
         }
     }
 
@@ -3399,7 +3415,7 @@ class basic_json
             return m_value.array->operator[](idx);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3429,7 +3445,7 @@ class basic_json
             return m_value.array->operator[](idx);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3475,7 +3491,7 @@ class basic_json
             return m_value.object->operator[](key);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3517,7 +3533,7 @@ class basic_json
             return m_value.object->find(key)->second;
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3632,7 +3648,7 @@ class basic_json
             return m_value.object->operator[](key);
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3675,7 +3691,7 @@ class basic_json
             return m_value.object->find(key)->second;
         }
 
-        throw std::domain_error("cannot use operator[] with " + type_name());
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
     }
 
     /*!
@@ -3744,7 +3760,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use value() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
         }
     }
 
@@ -3806,17 +3822,17 @@ class basic_json
         if (is_object())
         {
             // if pointer resolves a value, return it or use default value
-            try
+            JSON_TRY
             {
                 return ptr.get_checked(this);
             }
-            catch (std::out_of_range&)
+            JSON_CATCH (std::out_of_range&)
             {
                 return default_value;
             }
         }
 
-        throw std::domain_error("cannot use value() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
     }
 
     /*!
@@ -3967,7 +3983,7 @@ class basic_json
         // make sure iterator fits the current value
         if (this != pos.m_object)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         IteratorType result = end();
@@ -3982,7 +3998,7 @@ class basic_json
             {
                 if (not pos.m_it.primitive_iterator.is_begin())
                 {
-                    throw std::out_of_range("iterator out of range");
+                    JSON_THROW(std::out_of_range("iterator out of range"));
                 }
 
                 if (is_string())
@@ -4012,7 +4028,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use erase() with " + type_name());
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
             }
         }
 
@@ -4074,7 +4090,7 @@ class basic_json
         // make sure iterator fits the current value
         if (this != first.m_object or this != last.m_object)
         {
-            throw std::domain_error("iterators do not fit current value");
+            JSON_THROW(std::domain_error("iterators do not fit current value"));
         }
 
         IteratorType result = end();
@@ -4089,7 +4105,7 @@ class basic_json
             {
                 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
                 {
-                    throw std::out_of_range("iterators out of range");
+                    JSON_THROW(std::out_of_range("iterators out of range"));
                 }
 
                 if (is_string())
@@ -4121,7 +4137,7 @@ class basic_json
 
             default:
             {
-                throw std::domain_error("cannot use erase() with " + type_name());
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
             }
         }
 
@@ -4165,7 +4181,7 @@ class basic_json
             return m_value.object->erase(key);
         }
 
-        throw std::domain_error("cannot use erase() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
     }
 
     /*!
@@ -4199,14 +4215,14 @@ class basic_json
         {
             if (idx >= size())
             {
-                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
             }
 
             m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
         }
         else
         {
-            throw std::domain_error("cannot use erase() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
         }
     }
 
@@ -4924,7 +4940,7 @@ class basic_json
         // push_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -4960,7 +4976,7 @@ class basic_json
         // push_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -5010,7 +5026,7 @@ class basic_json
         // push_back only works for null objects or objects
         if (not(is_null() or is_object()))
         {
-            throw std::domain_error("cannot use push_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
         }
 
         // transform null object into an object
@@ -5110,7 +5126,7 @@ class basic_json
         // emplace_back only works for null objects or arrays
         if (not(is_null() or is_array()))
         {
-            throw std::domain_error("cannot use emplace_back() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name()));
         }
 
         // transform null object into an array
@@ -5158,7 +5174,7 @@ class basic_json
         // emplace only works for null objects or arrays
         if (not(is_null() or is_object()))
         {
-            throw std::domain_error("cannot use emplace() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use emplace() with " + type_name()));
         }
 
         // transform null object into an object
@@ -5209,7 +5225,7 @@ class basic_json
             // check if iterator pos fits to this JSON value
             if (pos.m_object != this)
             {
-                throw std::domain_error("iterator does not fit current value");
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
             }
 
             // insert to array and return iterator
@@ -5218,7 +5234,7 @@ class basic_json
             return result;
         }
 
-        throw std::domain_error("cannot use insert() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
     }
 
     /*!
@@ -5262,7 +5278,7 @@ class basic_json
             // check if iterator pos fits to this JSON value
             if (pos.m_object != this)
             {
-                throw std::domain_error("iterator does not fit current value");
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
             }
 
             // insert to array and return iterator
@@ -5271,7 +5287,7 @@ class basic_json
             return result;
         }
 
-        throw std::domain_error("cannot use insert() with " + type_name());
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
     }
 
     /*!
@@ -5309,24 +5325,24 @@ class basic_json
         // insert only works for arrays
         if (not is_array())
         {
-            throw std::domain_error("cannot use insert() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
         }
 
         // check if iterator pos fits to this JSON value
         if (pos.m_object != this)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         // check if range iterators belong to the same JSON object
         if (first.m_object != last.m_object)
         {
-            throw std::domain_error("iterators do not fit");
+            JSON_THROW(std::domain_error("iterators do not fit"));
         }
 
         if (first.m_object == this or last.m_object == this)
         {
-            throw std::domain_error("passed iterators may not belong to container");
+            JSON_THROW(std::domain_error("passed iterators may not belong to container"));
         }
 
         // insert to array and return iterator
@@ -5367,13 +5383,13 @@ class basic_json
         // insert only works for arrays
         if (not is_array())
         {
-            throw std::domain_error("cannot use insert() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
         }
 
         // check if iterator pos fits to this JSON value
         if (pos.m_object != this)
         {
-            throw std::domain_error("iterator does not fit current value");
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
         }
 
         // insert to array and return iterator
@@ -5440,7 +5456,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -5473,7 +5489,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -5506,7 +5522,7 @@ class basic_json
         }
         else
         {
-            throw std::domain_error("cannot use swap() with " + type_name());
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
         }
     }
 
@@ -6350,7 +6366,7 @@ class basic_json
     {
         if (current_index + sizeof(T) + 1 > vec.size())
         {
-            throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector");
+            JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"));
         }
 
         T result;
@@ -6900,19 +6916,19 @@ class basic_json
         // simple case: requested length is greater than the vector's length
         if (len > size or offset > size)
         {
-            throw std::out_of_range("len out of range");
+            JSON_THROW(std::out_of_range("len out of range"));
         }
 
         // second case: adding offset would result in overflow
         if ((size > (std::numeric_limits<size_t>::max() - offset)))
         {
-            throw std::out_of_range("len+offset out of range");
+            JSON_THROW(std::out_of_range("len+offset out of range"));
         }
 
         // last case: reading past the end of the vector
         if (len + offset > size)
         {
-            throw std::out_of_range("len+offset out of range");
+            JSON_THROW(std::out_of_range("len+offset out of range"));
         }
     }
 
@@ -7148,7 +7164,7 @@ class basic_json
 
                 default:
                 {
-                    throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+                    JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
                 }
             }
         }
@@ -7631,7 +7647,7 @@ class basic_json
 
             default: // anything else (0xFF is handled inside the other types)
             {
-                throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+                JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
             }
         }
     }
@@ -8521,7 +8537,7 @@ class basic_json
 
                 case basic_json::value_t::null:
                 {
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
 
                 default:
@@ -8531,7 +8547,7 @@ class basic_json
                         return *m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8565,7 +8581,7 @@ class basic_json
                         return m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8665,7 +8681,7 @@ class basic_json
             // if objects are not the same, the comparison is undefined
             if (m_object != other.m_object)
             {
-                throw std::domain_error("cannot compare iterators of different containers");
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
             }
 
             assert(m_object != nullptr);
@@ -8707,7 +8723,7 @@ class basic_json
             // if objects are not the same, the comparison is undefined
             if (m_object != other.m_object)
             {
-                throw std::domain_error("cannot compare iterators of different containers");
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
             }
 
             assert(m_object != nullptr);
@@ -8716,7 +8732,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot compare order of object iterators");
+                    JSON_THROW(std::domain_error("cannot compare order of object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8770,7 +8786,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use offsets with object iterators");
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8832,7 +8848,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use offsets with object iterators");
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8859,7 +8875,7 @@ class basic_json
             {
                 case basic_json::value_t::object:
                 {
-                    throw std::domain_error("cannot use operator[] for object iterators");
+                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
                 }
 
                 case basic_json::value_t::array:
@@ -8869,7 +8885,7 @@ class basic_json
 
                 case basic_json::value_t::null:
                 {
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
 
                 default:
@@ -8879,7 +8895,7 @@ class basic_json
                         return *m_object;
                     }
 
-                    throw std::out_of_range("cannot get value");
+                    JSON_THROW(std::out_of_range("cannot get value"));
                 }
             }
         }
@@ -8897,7 +8913,7 @@ class basic_json
                 return m_it.object_iterator->first;
             }
 
-            throw std::domain_error("cannot use key() for non-object iterators");
+            JSON_THROW(std::domain_error("cannot use key() for non-object iterators"));
         }
 
         /*!
@@ -9082,7 +9098,7 @@ class basic_json
             // immediately abort if stream is erroneous
             if (s.fail())
             {
-                throw std::invalid_argument("stream error");
+                JSON_THROW(std::invalid_argument("stream error"));
             }
 
             // fill buffer
@@ -9149,7 +9165,7 @@ class basic_json
                 }
                 else
                 {
-                    throw std::invalid_argument("missing or wrong low surrogate");
+                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
                 }
             }
 
@@ -9183,7 +9199,7 @@ class basic_json
             }
             else
             {
-                throw std::out_of_range("code points above 0x10FFFF are invalid");
+                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
             }
 
             return result;
@@ -9565,7 +9581,7 @@ class basic_json
                                 // make sure there is a subsequent unicode
                                 if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
                                 {
-                                    throw std::invalid_argument("missing low surrogate");
+                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
                                 }
 
                                 // get code yyyy from uxxxx\uyyyy
@@ -9578,7 +9594,7 @@ class basic_json
                             else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
                             {
                                 // we found a lone low surrogate
-                                throw std::invalid_argument("missing high surrogate");
+                                JSON_THROW(std::invalid_argument("missing high surrogate"));
                             }
                             else
                             {
@@ -10056,7 +10072,7 @@ class basic_json
                               "'") :
                               lexer::token_type_name(last_token));
                 error_msg += "; expected " + lexer::token_type_name(t);
-                throw std::invalid_argument(error_msg);
+                JSON_THROW(std::invalid_argument(error_msg));
             }
         }
 
@@ -10068,7 +10084,7 @@ class basic_json
                 error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
                               "'") :
                               lexer::token_type_name(last_token));
-                throw std::invalid_argument(error_msg);
+                JSON_THROW(std::invalid_argument(error_msg));
             }
         }
 
@@ -10164,7 +10180,7 @@ class basic_json
         {
             if (is_root())
             {
-                throw std::domain_error("JSON pointer has no parent");
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
             }
 
             auto last = reference_tokens.back();
@@ -10182,7 +10198,7 @@ class basic_json
         {
             if (is_root())
             {
-                throw std::domain_error("JSON pointer has no parent");
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
             }
 
             json_pointer result = *this;
@@ -10243,7 +10259,7 @@ class basic_json
                     */
                     default:
                     {
-                        throw std::domain_error("invalid value to unflatten");
+                        JSON_THROW(std::domain_error("invalid value to unflatten"));
                     }
                 }
             }
@@ -10311,7 +10327,7 @@ class basic_json
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         if (reference_token == "-")
@@ -10329,7 +10345,7 @@ class basic_json
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -10363,7 +10379,7 @@ class basic_json
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // note: at performs range check
@@ -10373,7 +10389,7 @@ class basic_json
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -10415,7 +10431,7 @@ class basic_json
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // use unchecked array access
@@ -10425,7 +10441,7 @@ class basic_json
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -10459,7 +10475,7 @@ class basic_json
                         // error condition (cf. RFC 6901, Sect. 4)
                         if (reference_token.size() > 1 and reference_token[0] == '0')
                         {
-                            throw std::domain_error("array index must not begin with '0'");
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
                         }
 
                         // note: at performs range check
@@ -10469,7 +10485,7 @@ class basic_json
 
                     default:
                     {
-                        throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
                     }
                 }
             }
@@ -10491,7 +10507,7 @@ class basic_json
             // check if nonempty reference string begins with slash
             if (reference_string[0] != '/')
             {
-                throw std::domain_error("JSON pointer must be empty or begin with '/'");
+                JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'"));
             }
 
             // extract the reference tokens:
@@ -10526,7 +10542,7 @@ class basic_json
                             (reference_token[pos + 1] != '0' and
                              reference_token[pos + 1] != '1'))
                     {
-                        throw std::domain_error("escape error: '~' must be followed with '0' or '1'");
+                        JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'"));
                     }
                 }
 
@@ -10652,7 +10668,7 @@ class basic_json
         {
             if (not value.is_object())
             {
-                throw std::domain_error("only objects can be unflattened");
+                JSON_THROW(std::domain_error("only objects can be unflattened"));
             }
 
             basic_json result;
@@ -10662,7 +10678,7 @@ class basic_json
             {
                 if (not element.second.is_primitive())
                 {
-                    throw std::domain_error("values in object must be primitive");
+                    JSON_THROW(std::domain_error("values in object must be primitive"));
                 }
 
                 // assign value to reference pointed to by JSON pointer; Note
@@ -10991,7 +11007,7 @@ class basic_json
                             if (static_cast<size_type>(idx) > parent.size())
                             {
                                 // avoid undefined behavior
-                                throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
+                                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
                             }
                             else
                             {
@@ -11029,7 +11045,7 @@ class basic_json
                 }
                 else
                 {
-                    throw std::out_of_range("key '" + last_path + "' not found");
+                    JSON_THROW(std::out_of_range("key '" + last_path + "' not found"));
                 }
             }
             else if (parent.is_array())
@@ -11043,7 +11059,7 @@ class basic_json
         if (not json_patch.is_array())
         {
             // a JSON patch must be an array of objects
-            throw std::invalid_argument("JSON patch must be an array of objects");
+            JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
         }
 
         // iterate and apply th eoperations
@@ -11063,13 +11079,13 @@ class basic_json
                 // check if desired value is present
                 if (it == val.m_value.object->end())
                 {
-                    throw std::invalid_argument(error_msg + " must have member '" + member + "'");
+                    JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'"));
                 }
 
                 // check if result is of type string
                 if (string_type and not it->second.is_string())
                 {
-                    throw std::invalid_argument(error_msg + " must have string member '" + member + "'");
+                    JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'"));
                 }
 
                 // no error: return value
@@ -11079,7 +11095,7 @@ class basic_json
             // type check
             if (not val.is_object())
             {
-                throw std::invalid_argument("JSON patch must be an array of objects");
+                JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
             }
 
             // collect mandatory members
@@ -11138,13 +11154,13 @@ class basic_json
                 case patch_operations::test:
                 {
                     bool success = false;
-                    try
+                    JSON_TRY
                     {
                         // check if "value" matches the one at "path"
                         // the "path" location must exist - use at()
                         success = (result.at(ptr) == get_value("test", "value", false));
                     }
-                    catch (std::out_of_range&)
+                    JSON_CATCH (std::out_of_range&)
                     {
                         // ignore out of range errors: success remains false
                     }
@@ -11152,7 +11168,7 @@ class basic_json
                     // throw an exception if test fails
                     if (not success)
                     {
-                        throw std::domain_error("unsuccessful: " + val.dump());
+                        JSON_THROW(std::domain_error("unsuccessful: " + val.dump()));
                     }
 
                     break;
@@ -11162,7 +11178,7 @@ class basic_json
                 {
                     // op must be "add", "remove", "replace", "move", "copy", or
                     // "test"
-                    throw std::invalid_argument("operation value '" + op + "' is invalid");
+                    JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid"));
                 }
             }
         }
@@ -11435,4 +11451,10 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
     #pragma GCC diagnostic pop
 #endif
 
+// clean up
+#undef JSON_THROW
+#undef JSON_TRY
+#undef JSON_CATCH
+#undef JSON_DEPRECATED
+
 #endif
diff --git a/test/Makefile b/test/Makefile
index 3d5595d2..0b235ba1 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -75,7 +75,7 @@ test-%: src/unit-%.cpp ../src/json.hpp thirdparty/catch/catch.hpp
 	@echo "[CXXLD] $@"
 	@$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -DCATCH_CONFIG_MAIN $< -o $@
 
-TEST_PATTERN = "*"
+TEST_PATTERN ?= "*"
 TEST_PREFIX = ""
 check: $(TESTCASES)
 	@cd .. ; for testcase in $(TESTCASES); do echo "Executing $$testcase..."; $(TEST_PREFIX)test/$$testcase $(TEST_PATTERN) || exit 1; done
diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp
index 92238b79..43f9f433 100644
--- a/test/src/unit-cbor.cpp
+++ b/test/src/unit-cbor.cpp
@@ -1187,7 +1187,7 @@ TEST_CASE("single CBOR roundtrip")
     }
 }
 
-TEST_CASE("CBOR regressions")
+TEST_CASE("CBOR regressions", "[!throws]")
 {
     SECTION("fuzz test results")
     {
diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp
index 1ba6aa61..f12da1e4 100644
--- a/test/src/unit-element_access2.cpp
+++ b/test/src/unit-element_access2.cpp
@@ -298,25 +298,6 @@ TEST_CASE("element access 2")
                     CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
                 }
 
-                SECTION("access non-existing value")
-                {
-                    CHECK(j.value("/not/existing"_json_pointer, 2) == 2);
-                    CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u);
-                    CHECK(j.value("/not/existing"_json_pointer, false) == false);
-                    CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar");
-                    CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
-                    CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
-                    CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
-
-                    CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2);
-                    CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u);
-                    CHECK(j_const.value("/not/existing"_json_pointer, false) == false);
-                    CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar");
-                    CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
-                    CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
-                    CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
-                }
-
                 SECTION("access on non-object type")
                 {
                     SECTION("null")
@@ -957,3 +938,37 @@ TEST_CASE("element access 2")
         }
     }
 }
+
+TEST_CASE("element access 2 (throwing tests)", "[!throws]")
+{
+    SECTION("object")
+    {
+        json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}};
+        const json j_const = j;
+
+        SECTION("access specified element with default value")
+        {
+            SECTION("given a JSON pointer")
+            {
+                SECTION("access non-existing value")
+                {
+                    CHECK(j.value("/not/existing"_json_pointer, 2) == 2);
+                    CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u);
+                    CHECK(j.value("/not/existing"_json_pointer, false) == false);
+                    CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar");
+                    CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
+                    CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
+                    CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
+
+                    CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2);
+                    CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u);
+                    CHECK(j_const.value("/not/existing"_json_pointer, false) == false);
+                    CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar");
+                    CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
+                    CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
+                    CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
+                }
+            }
+        }
+    }
+}