diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## [0.10.1.0] - 2022-06-04
+
+### Changed
+
+* Fixed a bug where multiple layers of contextual failures were not unwrapped and shown correctly.
+* Made 'Assertion' fields strict.
+
 ## [0.10.0.0] - 2022-04-28
 
 ### Added
diff --git a/output-test/Spec.hs b/output-test/Spec.hs
--- a/output-test/Spec.hs
+++ b/output-test/Spec.hs
@@ -206,6 +206,7 @@
             True `shouldBe` False
     it "shows a context when an exception is thrown as well" $
       context "context" (undefined :: IO ())
+
   modifyMaxSize (`div` 10) $
     describe "Property" $ do
       describe "0 tests run" $ modifyMaxSuccess (const 0) $ it "shows a red '0 tests' when no tests are run" $ property $ \b -> b `shouldBe` False
diff --git a/src/Test/Syd/Expectation.hs b/src/Test/Syd/Expectation.hs
--- a/src/Test/Syd/Expectation.hs
+++ b/src/Test/Syd/Expectation.hs
@@ -127,7 +127,9 @@
 -- This is a completely different function from the function with the same name in hspec.
 -- In hspec, context is a synonym for describe, but in sydtest, context is used for contextual failures.
 context :: String -> IO a -> IO a
-context s action = (action >>= evaluate) `catch` (\e -> throwIO (addContextToException (e :: SomeException) s))
+context s action =
+  (action >>= evaluate)
+    `catch` (\(SomeException e) -> throwIO (addContextToException e s))
 
 -- | For easy hspec migration
 type Expectation = IO ()
diff --git a/src/Test/Syd/Output.hs b/src/Test/Syd/Output.hs
--- a/src/Test/Syd/Output.hs
+++ b/src/Test/Syd/Output.hs
@@ -230,22 +230,22 @@
   | M.null labels = []
   | map fst (M.toList labels) == [[]] = []
   | otherwise =
-    [chunk "Labels"] :
-    map
-      ( pad
-          . ( \(ss, i) ->
-                [ chunk
-                    ( T.pack
-                        ( printf
-                            "%5.2f%% %s"
-                            (100 * fromIntegral i / fromIntegral totalCount :: Double)
-                            (commaList (map show ss))
-                        )
-                    )
-                ]
-            )
-      )
-      (M.toList labels)
+      [chunk "Labels"] :
+      map
+        ( pad
+            . ( \(ss, i) ->
+                  [ chunk
+                      ( T.pack
+                          ( printf
+                              "%5.2f%% %s"
+                              (100 * fromIntegral i / fromIntegral totalCount :: Double)
+                              (commaList (map show ss))
+                          )
+                      )
+                  ]
+              )
+        )
+        (M.toList labels)
   where
     pad = (chunk (T.pack (replicate paddingSize ' ')) :)
 
@@ -254,19 +254,19 @@
 classesChunks (Just classes)
   | M.null classes = []
   | otherwise =
-    [chunk "Classes"] :
-    map
-      ( pad
-          . ( \(s, i) ->
-                [ chunk
-                    ( T.pack
-                        ( printf "%5.2f%% %s" (100 * fromIntegral i / fromIntegral total :: Double) s
-                        )
-                    )
-                ]
-            )
-      )
-      (M.toList classes)
+      [chunk "Classes"] :
+      map
+        ( pad
+            . ( \(s, i) ->
+                  [ chunk
+                      ( T.pack
+                          ( printf "%5.2f%% %s" (100 * fromIntegral i / fromIntegral total :: Double) s
+                          )
+                      )
+                  ]
+              )
+        )
+        (M.toList classes)
   where
     pad = (chunk (T.pack (replicate paddingSize ' ')) :)
     total = sum $ map snd $ M.toList classes
@@ -392,12 +392,13 @@
                 ]
 
 outputSomeException :: SomeException -> [[Chunk]]
-outputSomeException se =
-  case fromException se of
-    Just (Contextual se' s) -> outputSomeException se' ++ stringChunks s
-    Nothing -> case fromException se of
-      Just a -> outputAssertion a
-      Nothing -> stringChunks $ displayException se
+outputSomeException outerException =
+  case fromException outerException :: Maybe Contextual of
+    Just (Contextual innerException s) -> outputSomeException (SomeException innerException) ++ stringChunks s
+    Nothing ->
+      case fromException outerException :: Maybe Assertion of
+        Just a -> outputAssertion a
+        Nothing -> stringChunks $ displayException outerException
 
 outputAssertion :: Assertion -> [[Chunk]]
 outputAssertion = \case
diff --git a/src/Test/Syd/Run.hs b/src/Test/Syd/Run.hs
--- a/src/Test/Syd/Run.hs
+++ b/src/Test/Syd/Run.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -449,27 +450,35 @@
 --
 -- You will probably not want to use this directly in everyday tests, use `shouldBe` or a similar function instead.
 data Assertion
-  = NotEqualButShouldHaveBeenEqual String String
-  | EqualButShouldNotHaveBeenEqual String String
+  = NotEqualButShouldHaveBeenEqual !String !String
+  | EqualButShouldNotHaveBeenEqual !String !String
   | PredicateSucceededButShouldHaveFailed
-      String -- Value
-      (Maybe String) -- Name of the predicate
+      !String -- Value
+      !(Maybe String) -- Name of the predicate
   | PredicateFailedButShouldHaveSucceeded
-      String -- Value
-      (Maybe String) -- Name of the predicate
-  | ExpectationFailed String
-  | Context Assertion String
+      !String -- Value
+      !(Maybe String) -- Name of the predicate
+  | ExpectationFailed !String
+  | Context !Assertion !String
   deriving (Show, Eq, Typeable, Generic)
 
 instance Exception Assertion
 
-data Contextual = Contextual !SomeException !String
-  deriving (Show, Typeable, Generic)
+-- | An exception with context.
+--
+-- We wrap an existentially qualified exception here, instead of
+-- 'SomeException', so that we can unwrap it.
+-- (For some unknown reason, that doesn't work otherwise.)
+data Contextual
+  = forall e. Exception e => Contextual !e !String
 
+instance Show Contextual where
+  showsPrec d (Contextual e s) = showParen (d > 10) $ showString "Contextual " . showsPrec 11 (displayException e) . showString " " . showsPrec 11 s
+
 instance Exception Contextual
 
 addContextToException :: Exception e => e -> String -> Contextual
-addContextToException e = Contextual (SomeException e)
+addContextToException e = Contextual e
 
 data GoldenCase
   = GoldenNotFound
diff --git a/src/Test/Syd/Runner/Synchronous.hs b/src/Test/Syd/Runner/Synchronous.hs
--- a/src/Test/Syd/Runner/Synchronous.hs
+++ b/src/Test/Syd/Runner/Synchronous.hs
@@ -151,10 +151,10 @@
       go i
         | i <= 1 = runFunc
         | otherwise = do
-          result <- runFunc
-          case testRunResultStatus result of
-            TestPassed -> pure result
-            TestFailed -> updateRetriesResult <$> go (pred i)
+            result <- runFunc
+            case testRunResultStatus result of
+              TestPassed -> pure result
+              TestFailed -> updateRetriesResult <$> go (pred i)
         where
           updateRetriesResult :: TestRunResult -> TestRunResult
           updateRetriesResult trr =
diff --git a/sydtest.cabal b/sydtest.cabal
--- a/sydtest.cabal
+++ b/sydtest.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           sydtest
-version:        0.10.0.0
+version:        0.10.1.0
 synopsis:       A modern testing framework for Haskell with good defaults and advanced testing features.
 description:    A modern testing framework for Haskell with good defaults and advanced testing features. Sydtest aims to make the common easy and the hard possible. See https://github.com/NorfairKing/sydtest#readme for more information.
 category:       Testing
