diff --git a/tests/unit/unit_main.cpp b/tests/unit/unit_main.cpp
index 7ca861716..3f6642c0c 100644
--- a/tests/unit/unit_main.cpp
+++ b/tests/unit/unit_main.cpp
@@ -26,7 +26,11 @@ int main(int argc, char** argv) {
 #ifdef TTG_EXECUTABLE
   // ttg::launch_lldb();
   // ttg::launch_gdb();
+  assert(!ttg::initialized());
+  assert(!ttg::finalized());
   ttg::initialize(argc, argv);
+  assert(ttg::initialized());
+  assert(!ttg::finalized());
   ttg::diagnose_off();  // turn off diagnostics
 
   const auto nranks = ttg::default_execution_context().size();
@@ -41,6 +45,8 @@ int main(int argc, char** argv) {
 #ifdef TTG_EXECUTABLE
   ttg::fence();
   ttg::finalize();
+  assert(!ttg::initialized());
+  assert(ttg::finalized());
 #endif
 
   return result;
diff --git a/ttg/ttg/run.h b/ttg/ttg/run.h
index 21ec337e8..845bad097 100644
--- a/ttg/ttg/run.h
+++ b/ttg/ttg/run.h
@@ -12,6 +12,29 @@
 
 namespace ttg {
 
+  namespace detail {
+    inline bool& initialized_accessor() {
+      static bool flag = false;
+      return flag;
+    }
+    inline bool& finalized_accessor() {
+      static bool flag = false;
+      return flag;
+    }
+  }
+
+  /// checks whether TTG has been initialized
+  /// @return true if TTG has been initialized
+  inline bool initialized() {
+    return detail::initialized_accessor();
+  }
+
+  /// checks whether TTG has been initialized
+  /// @return true if TTG has been initialized
+  inline bool finalized() {
+    return detail::finalized_accessor();
+  }
+
   /// Initializes the TTG runtime with the default backend
 
   /// @note Dispatches to the default backend's `ttg_initialize`.
@@ -28,21 +51,31 @@ namespace ttg {
   ///        most users will want to omit this
   template <typename... RestOfArgs>
   inline void initialize(int argc, char** argv, int num_threads, RestOfArgs&&... args) {
-    // if requested by user, create a Debugger object
-    if (auto debugger_cstr = std::getenv("TTG_DEBUGGER")) {
-      using ttg::Debugger;
-      auto debugger = std::make_shared<Debugger>();
-      Debugger::set_default_debugger(debugger);
-      debugger->set_exec(argv[0]);
-      debugger->set_cmd(debugger_cstr);
+    if (!initialized()) {
+      if (finalized()) {
+        throw std::runtime_error("ttg::initialize(): TTG already finalized, cannot be re-initialized");
+      }
+
+      // if requested by user, create a Debugger object
+      if (auto debugger_cstr = std::getenv("TTG_DEBUGGER")) {
+        using ttg::Debugger;
+        auto debugger = std::make_shared<Debugger>();
+        Debugger::set_default_debugger(debugger);
+        debugger->set_exec(argv[0]);
+        debugger->set_cmd(debugger_cstr);
+      }
+
+      if (num_threads < 1) num_threads = detail::num_threads();
+      TTG_IMPL_NS::ttg_initialize(argc, argv, num_threads, std::forward<RestOfArgs>(args)...);
+
+      // finish setting up the Debugger, if needed
+      if (ttg::Debugger::default_debugger())
+        ttg::Debugger::default_debugger()->set_prefix(ttg::default_execution_context().rank());
+
+      detail::initialized_accessor() = true;
     }
-
-    if (num_threads < 1) num_threads = detail::num_threads();
-    TTG_IMPL_NS::ttg_initialize(argc, argv, num_threads, std::forward<RestOfArgs>(args)...);
-
-    // finish setting up the Debugger, if needed
-    if (ttg::Debugger::default_debugger())
-      ttg::Debugger::default_debugger()->set_prefix(ttg::default_execution_context().rank());
+    else
+      throw std::runtime_error("ttg::initialize(): TTG already initialized");
   }
 
   /// Finalizes the TTG runtime
@@ -54,7 +87,15 @@ namespace ttg {
   /// `initialize` call
   /// @internal ENABLE_WHEN_TTG_CAN_MULTIBACKEND To finalize the TTG runtime with multiple backends must call the
   /// corresponding `ttg_finalize` functions explicitly.
-  inline void finalize() { TTG_IMPL_NS::ttg_finalize(); }
+  inline void finalize() {
+    if (initialized()) {
+      TTG_IMPL_NS::ttg_finalize();
+      detail::initialized_accessor() = false;
+      detail::finalized_accessor() = true;
+    }
+    else
+      throw std::runtime_error("ttg::finalize(): TTG has not been initialized yet");
+  }
 
   /// Aborts the TTG program using the default backend's `ttg_abort` method
   inline void abort() { TTG_IMPL_NS::ttg_abort(); }