diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
 Changes
 =======
 
+Version 0.10.1
+--------------
+
+Export `Test.Tasty.Runners.formatMessage`
+
 Version 0.10.0.4
 ----------------
 
diff --git a/Test/Tasty/Ingredients/ConsoleReporter.hs b/Test/Tasty/Ingredients/ConsoleReporter.hs
--- a/Test/Tasty/Ingredients/ConsoleReporter.hs
+++ b/Test/Tasty/Ingredients/ConsoleReporter.hs
@@ -12,13 +12,13 @@
 import Control.Monad.Reader hiding (fail,reader)
 import Control.Concurrent.STM
 import Control.Exception
-import Control.DeepSeq
 import Control.Applicative
 import Test.Tasty.Core
 import Test.Tasty.Run
 import Test.Tasty.Ingredients
 import Test.Tasty.Options
 import Test.Tasty.Runners.Reducers
+import Test.Tasty.Runners.Utils
 import Text.Printf
 import qualified Data.IntMap as IntMap
 import Data.Char
@@ -461,22 +461,6 @@
       case m 0 of
         MinusInfinity -> 0
         Maximum x -> x
-
--- | Printing exceptions or other messages is tricky — in the process we
--- can get new exceptions!
---
--- See e.g. https://github.com/feuerbach/tasty/issues/25
-formatMessage :: String -> IO String
-formatMessage msg = go 3 msg
-  where
-    -- to avoid infinite recursion, we introduce the recursion limit
-    go :: Int -> String -> IO String
-    go 0        _ = return "exceptions keep throwing other exceptions!"
-    go recLimit msg = do
-      mbStr <- try $ evaluate $ force msg
-      case mbStr of
-        Right str -> return str
-        Left e' -> printf "message threw an exception: %s" <$> go (recLimit-1) (show (e' :: SomeException))
 
 -- (Potentially) colorful output
 ok, fail, infoOk, infoFail :: (?colors :: Bool) => String -> IO ()
diff --git a/Test/Tasty/Runners.hs b/Test/Tasty/Runners.hs
--- a/Test/Tasty/Runners.hs
+++ b/Test/Tasty/Runners.hs
@@ -44,6 +44,8 @@
   , coreOptions
     -- ** Patterns
   , module Test.Tasty.Patterns
+    -- * Utilities
+  , module Test.Tasty.Runners.Utils
   )
   where
 
@@ -55,3 +57,4 @@
 import Test.Tasty.CmdLine
 import Test.Tasty.Ingredients.Basic
 import Test.Tasty.Runners.Reducers
+import Test.Tasty.Runners.Utils
diff --git a/Test/Tasty/Runners/Utils.hs b/Test/Tasty/Runners/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Test/Tasty/Runners/Utils.hs
@@ -0,0 +1,26 @@
+-- | Note: this module is re-exported as a whole from "Test.Tasty.Runners"
+module Test.Tasty.Runners.Utils where
+
+import Control.Exception
+import Control.DeepSeq
+import Control.Applicative
+import Text.Printf
+
+-- | Catch possible exceptions that may arise when evaluating a string.
+-- For normal (total) strings, this is a no-op.
+--
+-- This function should be used to display messages generated by the test
+-- suite (such as test result descriptions).
+--
+-- See e.g. <https://github.com/feuerbach/tasty/issues/25>
+formatMessage :: String -> IO String
+formatMessage msg = go 3 msg
+  where
+    -- to avoid infinite recursion, we introduce the recursion limit
+    go :: Int -> String -> IO String
+    go 0        _ = return "exceptions keep throwing other exceptions!"
+    go recLimit msg = do
+      mbStr <- try $ evaluate $ force msg
+      case mbStr of
+        Right str -> return str
+        Left e' -> printf "message threw an exception: %s" <$> go (recLimit-1) (show (e' :: SomeException))
diff --git a/tasty.cabal b/tasty.cabal
--- a/tasty.cabal
+++ b/tasty.cabal
@@ -2,7 +2,7 @@
 --  see http://haskell.org/cabal/users-guide/
 
 name:                tasty
-version:             0.10.0.4
+version:             0.10.1
 synopsis:            Modern and extensible testing framework
 description:         Tasty is a modern testing framework for Haskell.
                      It lets you combine your unit tests, golden
@@ -42,6 +42,7 @@
     Test.Tasty.Patterns,
     Test.Tasty.Run,
     Test.Tasty.Runners.Reducers,
+    Test.Tasty.Runners.Utils,
     Test.Tasty.CmdLine,
     Test.Tasty.Ingredients.ConsoleReporter
     Test.Tasty.Ingredients.ListTests
