diff --git a/src/cbmc/bmc.cpp b/src/cbmc/bmc.cpp
index 5865f49f154..0a75c2d5d5c 100644
--- a/src/cbmc/bmc.cpp
+++ b/src/cbmc/bmc.cpp
@@ -14,6 +14,7 @@ Author: Daniel Kroening, kroening@kroening.com
 #include <chrono>
 #include <iostream>
 
+#include <util/exception_utils.h>
 #include <util/exit_codes.h>
 
 #include <langapi/language_util.h>
@@ -296,9 +297,8 @@ void bmct::get_memory_model()
     memory_model=util_make_unique<memory_model_psot>(ns);
   else
   {
-    error() << "Invalid memory model " << mm
-            << " -- use one of sc, tso, pso" << eom;
-    throw "invalid memory model";
+    throw invalid_user_input_exceptiont(
+      "Invalid parameter " + mm, "--mm", "values of sc, tso, pso");
   }
 }
 
diff --git a/src/cbmc/bv_cbmc.cpp b/src/cbmc/bv_cbmc.cpp
index 019982f6fd7..faa0160bc27 100644
--- a/src/cbmc/bv_cbmc.cpp
+++ b/src/cbmc/bv_cbmc.cpp
@@ -9,16 +9,13 @@ Author: Daniel Kroening, kroening@kroening.com
 #include "bv_cbmc.h"
 
 #include <util/arith_tools.h>
+#include <util/invariant.h>
 #include <util/replace_expr.h>
 
 bvt bv_cbmct::convert_waitfor(const exprt &expr)
 {
-  if(expr.operands().size()!=4)
-  {
-    error().source_location=expr.find_source_location();
-    error() << "waitfor expected to have four operands" << eom;
-    throw 0;
-  }
+  DATA_INVARIANT(expr.operands().size() != 4,
+  	"waitfor expression is expected to have four operands");
 
   const exprt &old_cycle=expr.op0();
   const exprt &cycle_var=expr.op1();
@@ -27,12 +24,8 @@ bvt bv_cbmct::convert_waitfor(const exprt &expr)
   const exprt new_cycle = make_free_bv_expr(expr.type());
 
   mp_integer bound_value;
-  if(to_integer(bound, bound_value))
-  {
-    error().source_location=expr.find_source_location();
-    error() << "waitfor bound must be a constant" << eom;
-    throw 0;
-  }
+  bool successful_cast = to_integer(bound, bound_value);
+  INVARIANT(successful_cast, "waitfor bound must be a constant");
 
   {
     // constraint: new_cycle>=old_cycle
diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp
index b5ea4553f17..b52f0001b4c 100644
--- a/src/cbmc/cbmc_parse_options.cpp
+++ b/src/cbmc/cbmc_parse_options.cpp
@@ -67,7 +67,7 @@ Author: Daniel Kroening, kroening@kroening.com
 #include "version.h"
 
 cbmc_parse_optionst::cbmc_parse_optionst(int argc, const char **argv):
-  parse_options_baset(CBMC_OPTIONS, argc, argv),
+  parse_optionst(CBMC_OPTIONS, argc, argv, ui_message_handler),
   xml_interfacet(cmdline),
   messaget(ui_message_handler),
   ui_message_handler(cmdline, "CBMC " CBMC_VERSION),
@@ -79,7 +79,7 @@ ::cbmc_parse_optionst::cbmc_parse_optionst(
   int argc,
   const char **argv,
   const std::string &extra_options):
-  parse_options_baset(CBMC_OPTIONS+extra_options, argc, argv),
+  parse_optionst(CBMC_OPTIONS+extra_options, argc, argv, ui_message_handler),
   xml_interfacet(cmdline),
   messaget(ui_message_handler),
   ui_message_handler(cmdline, "CBMC " CBMC_VERSION),
diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h
index 24204c061b4..326ee7c0319 100644
--- a/src/cbmc/cbmc_parse_options.h
+++ b/src/cbmc/cbmc_parse_options.h
@@ -78,7 +78,7 @@ class optionst;
 // clang-format on
 
 class cbmc_parse_optionst:
-  public parse_options_baset,
+  public parse_optionst,
   public xml_interfacet,
   public messaget
 {
diff --git a/src/cbmc/cbmc_solvers.cpp b/src/cbmc/cbmc_solvers.cpp
index 8b216839f92..29ddcea3335 100644
--- a/src/cbmc/cbmc_solvers.cpp
+++ b/src/cbmc/cbmc_solvers.cpp
@@ -14,9 +14,11 @@ Author: Daniel Kroening, kroening@kroening.com
 #include <fstream>
 #include <iostream>
 #include <memory>
+#include <string>
 
-#include <util/unicode.h>
+#include <util/exception_utils.h>
 #include <util/make_unique.h>
+#include <util/unicode.h>
 
 #include <solvers/sat/satcheck.h>
 #include <solvers/refinement/bv_refinement.h>
@@ -168,8 +170,10 @@ std::unique_ptr<cbmc_solverst::solvert> cbmc_solverst::get_smt2(
   {
     if(solver==smt2_dect::solvert::GENERIC)
     {
-      error() << "please use --outfile" << eom;
-      throw 0;
+      throw invalid_user_input_exceptiont(
+        "Failed to provide a filename",
+        "--outfile",
+        "provide a filename with --outfile");
     }
 
     auto smt2_dec=
@@ -213,8 +217,8 @@ std::unique_ptr<cbmc_solverst::solvert> cbmc_solverst::get_smt2(
 
     if(!*out)
     {
-      error() << "failed to open " << filename << eom;
-      throw 0;
+      throw invalid_user_input_exceptiont(
+        "Failed to open suggested file: " + filename, "--outfile");
     }
 
     auto smt2_conv=
@@ -237,20 +241,38 @@ std::unique_ptr<cbmc_solverst::solvert> cbmc_solverst::get_smt2(
 
 void cbmc_solverst::no_beautification()
 {
-  if(options.get_bool_option("beautify"))
+  bool beautify = options.get_bool_option("beautify");
+
+  if(beautify)
   {
-    error() << "sorry, this solver does not support beautification" << eom;
-    throw 0;
+    throw invalid_user_input_exceptiont(
+      "Sorry, this solver does not support beautification",
+      "--beautify");
   }
 }
 
 void cbmc_solverst::no_incremental_check()
 {
-  if(options.get_bool_option("all-properties") ||
-     options.get_option("cover")!="" ||
-     options.get_option("incremental-check")!="")
+  bool all_properties = options.get_bool_option("all-properties");
+  bool cover = options.get_option("cover") != "";
+  bool incremental_check = options.get_option("incremental-check") != "";
+
+  if(all_properties)
+  {
+    throw invalid_user_input_exceptiont(
+      "Sorry, this solver does not support incremental solving",
+      "--all_properties");
+  }
+  else if(cover)
+  {
+    throw invalid_user_input_exceptiont(
+      "Sorry, this solver does not support incremental solving",
+      "--cover");
+  }
+  else if(incremental_check)
   {
-    error() << "sorry, this solver does not support incremental solving" << eom;
-    throw 0;
+    throw invalid_user_input_exceptiont(
+      "Sorry, this solver does not support incremental solving",
+      "--incremental-check");
   }
 }
diff --git a/src/cbmc/show_vcc.cpp b/src/cbmc/show_vcc.cpp
index 6a5b051cff9..677b33921c4 100644
--- a/src/cbmc/show_vcc.cpp
+++ b/src/cbmc/show_vcc.cpp
@@ -17,6 +17,7 @@ Author: Daniel Kroening, kroening@kroening.com
 #include <langapi/mode.h>
 #include <langapi/language_util.h>
 
+#include <util/exception_utils.h>
 #include <util/json.h>
 #include <util/json_expr.h>
 
@@ -143,7 +144,8 @@ void bmct::show_vcc()
   {
     of.open(filename);
     if(!of)
-      throw "failed to open file "+filename;
+      throw invalid_user_input_exceptiont(
+        "Failed to open file: " + filename, "--outfile");
   }
 
   std::ostream &out=have_file?of:std::cout;
diff --git a/src/util/exception_utils.h b/src/util/exception_utils.h
new file mode 100644
index 00000000000..73938fe1826
--- /dev/null
+++ b/src/util/exception_utils.h
@@ -0,0 +1,41 @@
+/*******************************************************************\
+
+Module: Exception helper utilities
+
+Author: Fotis Koutoulakis, fotis.koutoulakis@diffblue.com
+
+\*******************************************************************/
+
+#ifndef CPROVER_UTIL_EXCEPTION_UTILS_H
+#define CPROVER_UTIL_EXCEPTION_UTILS_H
+
+#include <string>
+
+class invalid_user_input_exceptiont
+{
+  std::string reason;
+  std::string option;
+  std::string correct_input;
+
+public:
+  invalid_user_input_exceptiont(
+    std::string reason,
+    std::string option,
+    std::string correct_input = "")
+    : reason(reason), option(option), correct_input(correct_input)
+  {
+  }
+
+  std::string what() const noexcept
+  {
+    std::string res;
+    res += "\nInvalid User Input Exception\n";
+    res += "Option: " + option + "\n";
+    res += "Reason: " + reason;
+    // Print an optional correct usage message assuming correct input parameters have been passed
+    res += correct_input.empty() ? "\n" : " Try: " + correct_input + "\n";
+    return res;
+  }
+};
+
+#endif // CPROVER_UTIL_EXCEPTION_UTILS_H
diff --git a/src/util/parse_options.cpp b/src/util/parse_options.cpp
index 2428c236889..08ddb7c00be 100644
--- a/src/util/parse_options.cpp
+++ b/src/util/parse_options.cpp
@@ -18,6 +18,8 @@ Author: Daniel Kroening, kroening@kroening.com
 #endif
 
 #include "cmdline.h"
+#include "exception_utils.h"
+#include "exit_codes.h"
 #include "signal_catcher.h"
 
 parse_options_baset::parse_options_baset(
@@ -82,3 +84,19 @@ banner_string(const std::string &front_end, const std::string &version)
   return "* *" + std::string(left_padding, ' ') + version_str +
          std::string(right_padding, ' ') + "* *";
 }
+
+int parse_optionst::main()
+{
+  // catch all exceptions here so that this code is not duplicated
+  // for each tool
+  try
+  {
+    return parse_options_baset::main();
+  }
+  catch(invalid_user_input_exceptiont &e)
+  {
+  	message.error() << e.what() << messaget::eom;
+  	return CPROVER_EXIT_EXCEPTION;
+  }
+  return CPROVER_EXIT_SUCCESS;
+}
diff --git a/src/util/parse_options.h b/src/util/parse_options.h
index 6b2b982fd51..cb210b96277 100644
--- a/src/util/parse_options.h
+++ b/src/util/parse_options.h
@@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com
 #include <string>
 
 #include "cmdline.h"
+#include "message.h"
 
 class parse_options_baset
 {
@@ -35,6 +36,25 @@ class parse_options_baset
   bool parse_result;
 };
 
+class parse_optionst: public parse_options_baset
+{
+public:
+  parse_optionst(
+    const std::string &optstring,
+    int argc,
+    const char **argv,
+    message_handlert &message_handler):
+    parse_options_baset(optstring, argc, argv),
+    message(message_handler)
+  {
+  }
+
+  int main() override;
+
+protected:
+  messaget message;
+};
+
 std::string
 banner_string(const std::string &front_end, const std::string &version);