diff --git a/emper/CountingPrivateSemaphore.cpp b/emper/CountingPrivateSemaphore.cpp
index d66634c77a22d90f5adee0113aeaaf53412c852c..3d559dba2a7c8841dd3793d90e1cb532bbb5f85b 100644
--- a/emper/CountingPrivateSemaphore.cpp
+++ b/emper/CountingPrivateSemaphore.cpp
@@ -1,10 +1,11 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020-2021 Florian Schmaus
+// Copyright © 2020-2022 Florian Schmaus
 #include "CountingPrivateSemaphore.hpp"
 
 #include <cassert>	// for assert
 
 #include "Context.hpp"	// for Context
+#include "Debug.hpp"
 
 CountingPrivateSemaphore::CountingPrivateSemaphore() : CountingPrivateSemaphore(0) {}
 
@@ -46,7 +47,7 @@ auto CountingPrivateSemaphore::signalInternal() -> Context* {
 		// returns nullptr. In this case the block() function will
 		// have won the race.
 		Context* context = blockedContext.exchange(nullptr);
-		assert(!context || context > (Context*)4096);
+		EMPER_ASSERT_MSG(!context || context > (Context*)4096, "Unexpected context value: " << context);
 		return context;
 	}
 
diff --git a/emper/Debug.hpp b/emper/Debug.hpp
index b6432a9979e734cdcb22d36c85908ac9eb2b798e..8be15afbebf3b77ea4fcc11945558bd966d8fb8c 100644
--- a/emper/Debug.hpp
+++ b/emper/Debug.hpp
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020-2021 Florian Schmaus, Florian Fischer
+// Copyright © 2020-2022 Florian Schmaus, Florian Fischer
 #pragma once
 
 #include <atomic>
@@ -8,6 +8,7 @@
 #include <string>
 #include <string_view>
 
+#include "Emper.hpp"
 #include "emper-config.h"
 #include "log/log.hpp"
 
@@ -26,6 +27,8 @@
 // NOLINTNEXTLINE(bugprone-macro-parentheses)
 #define LOG(level, x, log_func) do { if constexpr (level <= EMPER_LOG_LEVEL) { log_func(EMPER_BUILD_STR(x)); } } while (false)
 
+#define EMPER_ASSERT_MSG(expr, msg) do { if constexpr (emper::DEBUG) { if (!(expr)) { DIE_MSG(msg); } } } while (false)
+
 // NOLINTNEXTLINE(bugprone-macro-parentheses)
 #define DBG(x) LOG(Debug, x, emper::log::log_no_prefix);