diff --git a/signet.cabal b/signet.cabal
--- a/signet.cabal
+++ b/signet.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: signet
-version: 0.2025.5.12
+version: 0.2025.5.13
 synopsis: Standard Webhooks
 description:
   Signet is a Haskell library for working with Standard Webhooks.
@@ -83,6 +83,8 @@
     Signet.Unstable.Exception.SignetExceptionTest
     Signet.Unstable.Exception.ToleranceException
     Signet.Unstable.Exception.ToleranceExceptionTest
+    Signet.Unstable.Exception.UnknownSignature
+    Signet.Unstable.Exception.UnknownSignatureTest
     Signet.Unstable.Exception.VerificationException
     Signet.Unstable.Exception.VerificationExceptionTest
     Signet.Unstable.Extra.Either
@@ -118,8 +120,6 @@
     Signet.Unstable.Type.TimestampTest
     Signet.Unstable.Type.Tolerance
     Signet.Unstable.Type.ToleranceTest
-    Signet.Unstable.Type.UnknownSignature
-    Signet.Unstable.Type.UnknownSignatureTest
     Signet.Unstable.Type.Verifier
     Signet.Unstable.Type.VerifierTest
     Signet.UnstableTest
diff --git a/source/library/Signet.hs b/source/library/Signet.hs
--- a/source/library/Signet.hs
+++ b/source/library/Signet.hs
@@ -33,7 +33,6 @@
     Signet.Unstable.parseTimestamp,
     Signet.Unstable.Type.Tolerance.Tolerance (..),
     Signet.Unstable.typicalTolerance,
-    Signet.Unstable.Type.UnknownSignature.UnknownSignature (..),
     Signet.Unstable.Type.Verifier.Verifier (Signet.Unstable.AsymmetricVerifier, Signet.Unstable.SymmetricVerifier),
     Signet.Unstable.parseVerifier,
 
@@ -51,6 +50,7 @@
     Signet.Unstable.Exception.InvalidVerifier.InvalidVerifier (..),
     Signet.Unstable.Exception.SignetException.SignetException (..),
     Signet.Unstable.Exception.ToleranceException.ToleranceException (..),
+    Signet.Unstable.Exception.UnknownSignature.UnknownSignature (..),
     Signet.Unstable.Exception.VerificationException.VerificationException (..),
   )
 where
@@ -69,6 +69,7 @@
 import qualified Signet.Unstable.Exception.InvalidVerifier
 import qualified Signet.Unstable.Exception.SignetException
 import qualified Signet.Unstable.Exception.ToleranceException
+import qualified Signet.Unstable.Exception.UnknownSignature
 import qualified Signet.Unstable.Exception.VerificationException
 import qualified Signet.Unstable.Extra.Http
 import qualified Signet.Unstable.Type.AsymmetricSignature
@@ -84,5 +85,4 @@
 import qualified Signet.Unstable.Type.SymmetricSignature
 import qualified Signet.Unstable.Type.Timestamp
 import qualified Signet.Unstable.Type.Tolerance
-import qualified Signet.Unstable.Type.UnknownSignature
 import qualified Signet.Unstable.Type.Verifier
diff --git a/source/library/Signet/Unstable.hs b/source/library/Signet/Unstable.hs
--- a/source/library/Signet/Unstable.hs
+++ b/source/library/Signet/Unstable.hs
@@ -16,6 +16,7 @@
 import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp
 import qualified Signet.Unstable.Exception.InvalidVerifier as InvalidVerifier
 import qualified Signet.Unstable.Exception.SignetException as SignetException
+import qualified Signet.Unstable.Exception.UnknownSignature as UnknownSignature
 import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
 import qualified Signet.Unstable.Type.Id as Id
@@ -30,7 +31,6 @@
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
 import qualified Signet.Unstable.Type.Timestamp as Timestamp
 import qualified Signet.Unstable.Type.Tolerance as Tolerance
-import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
 import qualified Signet.Unstable.Type.Verifier as Verifier
 
 -- | Verifies a webhook with 'Text.Text' values. This is a wrapper around
diff --git a/source/library/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs b/source/library/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidAsymmetricSignatureTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidAsymmetricSignature" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidIdTest.hs b/source/library/Signet/Unstable/Exception/InvalidIdTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidIdTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidIdTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidId" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidMessageTest.hs b/source/library/Signet/Unstable/Exception/InvalidMessageTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidMessageTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidMessageTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidMessage" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidPublicKeyTest.hs b/source/library/Signet/Unstable/Exception/InvalidPublicKeyTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidPublicKeyTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidPublicKeyTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidPublicKey" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidSecretKeyTest.hs b/source/library/Signet/Unstable/Exception/InvalidSecretKeyTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidSecretKeyTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidSecretKeyTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidSecretKey" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidSecretTest.hs b/source/library/Signet/Unstable/Exception/InvalidSecretTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidSecretTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidSecretTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidSecret" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidSignatureTest.hs b/source/library/Signet/Unstable/Exception/InvalidSignatureTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidSignatureTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidSignatureTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidSignature" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidSignerTest.hs b/source/library/Signet/Unstable/Exception/InvalidSignerTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidSignerTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidSignerTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidSigner" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs b/source/library/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidSymmetricSignatureTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidSymmetricSignature" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidTimestampTest.hs b/source/library/Signet/Unstable/Exception/InvalidTimestampTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidTimestampTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidTimestampTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidTimestamp" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/InvalidVerifierTest.hs b/source/library/Signet/Unstable/Exception/InvalidVerifierTest.hs
--- a/source/library/Signet/Unstable/Exception/InvalidVerifierTest.hs
+++ b/source/library/Signet/Unstable/Exception/InvalidVerifierTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.InvalidVerifier" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/SignetExceptionTest.hs b/source/library/Signet/Unstable/Exception/SignetExceptionTest.hs
--- a/source/library/Signet/Unstable/Exception/SignetExceptionTest.hs
+++ b/source/library/Signet/Unstable/Exception/SignetExceptionTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.SignetException" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/ToleranceExceptionTest.hs b/source/library/Signet/Unstable/Exception/ToleranceExceptionTest.hs
--- a/source/library/Signet/Unstable/Exception/ToleranceExceptionTest.hs
+++ b/source/library/Signet/Unstable/Exception/ToleranceExceptionTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.ToleranceException" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Exception/UnknownSignature.hs b/source/library/Signet/Unstable/Exception/UnknownSignature.hs
new file mode 100644
--- /dev/null
+++ b/source/library/Signet/Unstable/Exception/UnknownSignature.hs
@@ -0,0 +1,14 @@
+module Signet.Unstable.Exception.UnknownSignature where
+
+import qualified Control.Monad.Catch as Exception
+import qualified Data.ByteString as ByteString
+
+newtype UnknownSignature
+  = MkUnknownSignature ByteString.ByteString
+  deriving (Eq, Show)
+
+instance Exception.Exception UnknownSignature where
+  displayException = mappend "unknown signature: " . show . unwrap
+
+unwrap :: UnknownSignature -> ByteString.ByteString
+unwrap (MkUnknownSignature byteString) = byteString
diff --git a/source/library/Signet/Unstable/Exception/UnknownSignatureTest.hs b/source/library/Signet/Unstable/Exception/UnknownSignatureTest.hs
new file mode 100644
--- /dev/null
+++ b/source/library/Signet/Unstable/Exception/UnknownSignatureTest.hs
@@ -0,0 +1,7 @@
+module Signet.Unstable.Exception.UnknownSignatureTest where
+
+import qualified Signet.Unstable.Type.Test as Test
+
+spec :: (Monad tree) => Test.Test io tree -> tree ()
+spec test = Test.describe test "Signet.Unstable.Exception.UnknownSignature" $ do
+  pure ()
diff --git a/source/library/Signet/Unstable/Exception/VerificationExceptionTest.hs b/source/library/Signet/Unstable/Exception/VerificationExceptionTest.hs
--- a/source/library/Signet/Unstable/Exception/VerificationExceptionTest.hs
+++ b/source/library/Signet/Unstable/Exception/VerificationExceptionTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Exception.VerificationException" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Extra/EitherTest.hs b/source/library/Signet/Unstable/Extra/EitherTest.hs
--- a/source/library/Signet/Unstable/Extra/EitherTest.hs
+++ b/source/library/Signet/Unstable/Extra/EitherTest.hs
@@ -5,7 +5,7 @@
 import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadCatch io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Extra.Either" $ do
   Test.describe test "hush" $ do
     Test.it test "works with Left" $ do
diff --git a/source/library/Signet/Unstable/Extra/HttpTest.hs b/source/library/Signet/Unstable/Extra/HttpTest.hs
--- a/source/library/Signet/Unstable/Extra/HttpTest.hs
+++ b/source/library/Signet/Unstable/Extra/HttpTest.hs
@@ -5,7 +5,7 @@
 import qualified Signet.Unstable.Extra.Http as Http
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Extra.Http" $ do
   Test.describe test "hWebhookId" $ do
     Test.it test "creates the correct header name" $ do
diff --git a/source/library/Signet/Unstable/Extra/MaybeTest.hs b/source/library/Signet/Unstable/Extra/MaybeTest.hs
--- a/source/library/Signet/Unstable/Extra/MaybeTest.hs
+++ b/source/library/Signet/Unstable/Extra/MaybeTest.hs
@@ -4,7 +4,7 @@
 import qualified Signet.Unstable.Extra.Maybe as Maybe
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Extra.Maybe" $ do
   Test.describe test "note" $ do
     Test.it test "works with nothing" $ do
diff --git a/source/library/Signet/Unstable/Type/AsymmetricSignatureTest.hs b/source/library/Signet/Unstable/Type/AsymmetricSignatureTest.hs
--- a/source/library/Signet/Unstable/Type/AsymmetricSignatureTest.hs
+++ b/source/library/Signet/Unstable/Type/AsymmetricSignatureTest.hs
@@ -1,13 +1,15 @@
 module Signet.Unstable.Type.AsymmetricSignatureTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Crypto.Error as Error
 import qualified Crypto.PubKey.Ed25519 as Ed25519
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.AsymmetricSignature" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid input" $ do
@@ -17,10 +19,10 @@
 
     Test.it test "succeeds with valid input" $ do
       let result = AsymmetricSignature.parse $ Ascii.pack "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
-      signature <- Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      signature <- Either.throw . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       Test.assertEq test result (Right $ AsymmetricSignature.MkAsymmetricSignature signature)
 
   Test.describe test "render" $ do
     Test.it test "works" $ do
-      asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      asymmetricSignature <- Either.throw . fmap AsymmetricSignature.MkAsymmetricSignature . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       Test.assertEq test (AsymmetricSignature.render asymmetricSignature) (Ascii.pack "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg==")
diff --git a/source/library/Signet/Unstable/Type/IdTest.hs b/source/library/Signet/Unstable/Type/IdTest.hs
--- a/source/library/Signet/Unstable/Type/IdTest.hs
+++ b/source/library/Signet/Unstable/Type/IdTest.hs
@@ -5,7 +5,7 @@
 import qualified Signet.Unstable.Type.Id as Id
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Id" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with input containing separator" $ do
diff --git a/source/library/Signet/Unstable/Type/MessageTest.hs b/source/library/Signet/Unstable/Type/MessageTest.hs
--- a/source/library/Signet/Unstable/Type/MessageTest.hs
+++ b/source/library/Signet/Unstable/Type/MessageTest.hs
@@ -1,5 +1,6 @@
 module Signet.Unstable.Type.MessageTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidMessage as InvalidMessage
 import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp
@@ -10,7 +11,7 @@
 import qualified Signet.Unstable.Type.Test as Test
 import qualified Signet.Unstable.Type.Timestamp as Timestamp
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Message" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid timestamp" $ do
diff --git a/source/library/Signet/Unstable/Type/PayloadTest.hs b/source/library/Signet/Unstable/Type/PayloadTest.hs
--- a/source/library/Signet/Unstable/Type/PayloadTest.hs
+++ b/source/library/Signet/Unstable/Type/PayloadTest.hs
@@ -2,6 +2,6 @@
 
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Payload" $ do
   pure ()
diff --git a/source/library/Signet/Unstable/Type/PublicKeyTest.hs b/source/library/Signet/Unstable/Type/PublicKeyTest.hs
--- a/source/library/Signet/Unstable/Type/PublicKeyTest.hs
+++ b/source/library/Signet/Unstable/Type/PublicKeyTest.hs
@@ -1,13 +1,15 @@
 module Signet.Unstable.Type.PublicKeyTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Crypto.Error as Error
 import qualified Crypto.PubKey.Ed25519 as Ed25519
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidPublicKey as InvalidPublicKey
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.PublicKey as PublicKey
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.PublicKey" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid prefix" $ do
@@ -22,10 +24,10 @@
 
     Test.it test "succeeds with valid input" $ do
       let result = PublicKey.parse $ Ascii.pack "whpk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="
-      publicKey <- fmap PublicKey.MkPublicKey . Error.throwCryptoErrorIO . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+      publicKey <- Either.throw . fmap PublicKey.MkPublicKey . Error.eitherCryptoError . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
       Test.assertEq test result (Right publicKey)
 
   Test.describe test "render" $ do
     Test.it test "works" $ do
-      publicKey <- fmap PublicKey.MkPublicKey . Error.throwCryptoErrorIO . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+      publicKey <- Either.throw . fmap PublicKey.MkPublicKey . Error.eitherCryptoError . Ed25519.publicKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
       Test.assertEq test (PublicKey.render publicKey) (Ascii.pack "whpk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU=")
diff --git a/source/library/Signet/Unstable/Type/SecretKeyTest.hs b/source/library/Signet/Unstable/Type/SecretKeyTest.hs
--- a/source/library/Signet/Unstable/Type/SecretKeyTest.hs
+++ b/source/library/Signet/Unstable/Type/SecretKeyTest.hs
@@ -1,13 +1,15 @@
 module Signet.Unstable.Type.SecretKeyTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Crypto.Error as Error
 import qualified Crypto.PubKey.Ed25519 as Ed25519
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidSecretKey as InvalidSecretKey
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.SecretKey as SecretKey
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.SecretKey" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid prefix" $ do
@@ -22,10 +24,10 @@
 
     Test.it test "succeeds with valid input" $ do
       let result = SecretKey.parse $ Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="
-      secretKey <- fmap SecretKey.MkSecretKey . Error.throwCryptoErrorIO . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+      secretKey <- Either.throw . fmap SecretKey.MkSecretKey . Error.eitherCryptoError . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
       Test.assertEq test result (Right secretKey)
 
   Test.describe test "render" $ do
     Test.it test "works" $ do
-      secretKey <- fmap SecretKey.MkSecretKey . Error.throwCryptoErrorIO . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+      secretKey <- Either.throw . fmap SecretKey.MkSecretKey . Error.eitherCryptoError . Ed25519.secretKey $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
       Test.assertEq test (SecretKey.render secretKey) (Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU=")
diff --git a/source/library/Signet/Unstable/Type/SecretTest.hs b/source/library/Signet/Unstable/Type/SecretTest.hs
--- a/source/library/Signet/Unstable/Type/SecretTest.hs
+++ b/source/library/Signet/Unstable/Type/SecretTest.hs
@@ -6,7 +6,7 @@
 import qualified Signet.Unstable.Type.Secret as Secret
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Secret" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid prefix" $ do
diff --git a/source/library/Signet/Unstable/Type/Signature.hs b/source/library/Signet/Unstable/Type/Signature.hs
--- a/source/library/Signet/Unstable/Type/Signature.hs
+++ b/source/library/Signet/Unstable/Type/Signature.hs
@@ -5,9 +5,9 @@
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Data.Word as Word
 import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature
+import qualified Signet.Unstable.Exception.UnknownSignature as UnknownSignature
 import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
-import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
 
 data Signature
   = Asymmetric AsymmetricSignature.AsymmetricSignature
diff --git a/source/library/Signet/Unstable/Type/SignatureTest.hs b/source/library/Signet/Unstable/Type/SignatureTest.hs
--- a/source/library/Signet/Unstable/Type/SignatureTest.hs
+++ b/source/library/Signet/Unstable/Type/SignatureTest.hs
@@ -1,5 +1,6 @@
 module Signet.Unstable.Type.SignatureTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Crypto.Error as Error
 import qualified Crypto.Hash as Hash
 import qualified Crypto.PubKey.Ed25519 as Ed25519
@@ -8,13 +9,14 @@
 import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature
 import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature
 import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature
+import qualified Signet.Unstable.Exception.UnknownSignature as UnknownSignature
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
 import qualified Signet.Unstable.Type.Signature as Signature
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
 import qualified Signet.Unstable.Type.Test as Test
-import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Signature" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid asymmetric signature" $ do
@@ -34,7 +36,7 @@
 
     Test.it test "succeeds with valid asymmetric signature" $ do
       let byteString = Ascii.pack "v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
-      signature <- fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      signature <- Either.throw . fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       Test.assertEq test (Signature.parse byteString) (Right (Right signature))
 
     Test.it test "succeeds with valid symmetric signature" $ do
@@ -44,7 +46,7 @@
 
   Test.describe test "render" $ do
     Test.it test "renders asymmetric signature correctly" $ do
-      signature <- fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      signature <- Either.throw . fmap (Signature.Asymmetric . AsymmetricSignature.MkAsymmetricSignature) . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       Test.assertEq test (Signature.render signature) (Ascii.pack "v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg==")
 
     Test.it test "renders symmetric signature correctly" $ do
diff --git a/source/library/Signet/Unstable/Type/Signatures.hs b/source/library/Signet/Unstable/Type/Signatures.hs
--- a/source/library/Signet/Unstable/Type/Signatures.hs
+++ b/source/library/Signet/Unstable/Type/Signatures.hs
@@ -4,8 +4,8 @@
 import qualified Data.Either as Either
 import qualified Data.Word as Word
 import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature
+import qualified Signet.Unstable.Exception.UnknownSignature as UnknownSignature
 import qualified Signet.Unstable.Type.Signature as Signature
-import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
 
 newtype Signatures
   = MkSignatures [Signature.Signature]
diff --git a/source/library/Signet/Unstable/Type/SignaturesTest.hs b/source/library/Signet/Unstable/Type/SignaturesTest.hs
--- a/source/library/Signet/Unstable/Type/SignaturesTest.hs
+++ b/source/library/Signet/Unstable/Type/SignaturesTest.hs
@@ -1,5 +1,6 @@
 module Signet.Unstable.Type.SignaturesTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Crypto.Error as Error
 import qualified Crypto.Hash as Hash
 import qualified Crypto.PubKey.Ed25519 as Ed25519
@@ -8,14 +9,15 @@
 import qualified Signet.Unstable.Exception.InvalidAsymmetricSignature as InvalidAsymmetricSignature
 import qualified Signet.Unstable.Exception.InvalidSignature as InvalidSignature
 import qualified Signet.Unstable.Exception.InvalidSymmetricSignature as InvalidSymmetricSignature
+import qualified Signet.Unstable.Exception.UnknownSignature as UnknownSignature
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.AsymmetricSignature as AsymmetricSignature
 import qualified Signet.Unstable.Type.Signature as Signature
 import qualified Signet.Unstable.Type.Signatures as Signatures
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
 import qualified Signet.Unstable.Type.Test as Test
-import qualified Signet.Unstable.Type.UnknownSignature as UnknownSignature
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Signatures" $ do
   Test.describe test "parse" $ do
     Test.it test "succeeds with no signatures" $ do
@@ -28,7 +30,7 @@
 
     Test.it test "succeeds with many signatures" $ do
       let symmetricSignature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty
-      asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      asymmetricSignature <- Either.throw . fmap AsymmetricSignature.MkAsymmetricSignature . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       let byteString = Ascii.pack "v1,47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= v1a,QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVotMDEyMzQ1Njc4OS1hYmNkZWZnaGlqa2xtbm9wcXJzdHV2cXh5eg=="
       let signatures =
             Signatures.MkSignatures
@@ -62,7 +64,7 @@
 
     Test.it test "renders many signatures" $ do
       let symmetricSignature = SymmetricSignature.MkSymmetricSignature $ Hash.hash ByteString.empty
-      asymmetricSignature <- fmap AsymmetricSignature.MkAsymmetricSignature . Error.throwCryptoErrorIO . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
+      asymmetricSignature <- Either.throw . fmap AsymmetricSignature.MkAsymmetricSignature . Error.eitherCryptoError . Ed25519.signature $ Ascii.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789-abcdefghijklmnopqrstuvqxyz"
       let signatures =
             Signatures.MkSignatures
               [ Signature.Symmetric symmetricSignature,
diff --git a/source/library/Signet/Unstable/Type/SignerTest.hs b/source/library/Signet/Unstable/Type/SignerTest.hs
--- a/source/library/Signet/Unstable/Type/SignerTest.hs
+++ b/source/library/Signet/Unstable/Type/SignerTest.hs
@@ -1,5 +1,6 @@
 module Signet.Unstable.Type.SignerTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidSigner as InvalidSigner
 import qualified Signet.Unstable.Extra.Either as Either
@@ -12,7 +13,7 @@
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Signer" $ do
   Test.describe test "parse" $ do
     Test.it test "succeeds with a valid secret key" $ do
@@ -48,14 +49,14 @@
       signer <- Either.throw . Signer.parse $ Ascii.pack "whsk_QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU="
       message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"
       let actual = Signer.sign signer message
-      Right expected <- Either.throw . Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="
+      expected <- Either.throw =<< Either.throw (Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ==")
       Test.assertEq test actual expected
 
     Test.it test "works with symmetric" $ do
       signer <- Either.throw . Signer.parse $ Ascii.pack "whsec_bXlzZWNyZXRrZXkxMjM0NQ=="
       message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"
       let actual = Signer.sign signer message
-      Right expected <- Either.throw . Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="
+      expected <- Either.throw =<< Either.throw (Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw=")
       Test.assertEq test actual expected
 
   Test.describe test "asymmetric" $ do
diff --git a/source/library/Signet/Unstable/Type/SymmetricSignatureTest.hs b/source/library/Signet/Unstable/Type/SymmetricSignatureTest.hs
--- a/source/library/Signet/Unstable/Type/SymmetricSignatureTest.hs
+++ b/source/library/Signet/Unstable/Type/SymmetricSignatureTest.hs
@@ -7,7 +7,7 @@
 import qualified Signet.Unstable.Type.SymmetricSignature as SymmetricSignature
 import qualified Signet.Unstable.Type.Test as Test
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.SymmetricSignature" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid symmetric signature" $ do
diff --git a/source/library/Signet/Unstable/Type/Test.hs b/source/library/Signet/Unstable/Type/Test.hs
--- a/source/library/Signet/Unstable/Type/Test.hs
+++ b/source/library/Signet/Unstable/Type/Test.hs
@@ -3,18 +3,21 @@
 module Signet.Unstable.Type.Test where
 
 import qualified Control.Monad as Monad
-import qualified Data.Void as Void
 import qualified GHC.Stack as Stack
 
-data Test spec = MkTest
-  { assertFailure :: (Stack.HasCallStack) => String -> IO Void.Void,
-    describe :: String -> spec () -> spec (),
-    it :: String -> IO () -> spec ()
+data Test io tree = MkTest
+  { assertFailure :: forall void. (Stack.HasCallStack) => String -> io void,
+    describe :: String -> tree () -> tree (),
+    it :: String -> io () -> tree ()
   }
 
-assertEq :: (Stack.HasCallStack, Eq a, Show a) => Test tree -> a -> a -> IO ()
+assertEq ::
+  (Stack.HasCallStack, Applicative io, Eq a, Show a) =>
+  Test io tree ->
+  a ->
+  a ->
+  io ()
 assertEq test expected actual =
   Monad.when (expected /= actual)
-    . Monad.void
     . assertFailure test
     $ "expected " <> show expected <> " but got " <> show actual
diff --git a/source/library/Signet/Unstable/Type/TimestampTest.hs b/source/library/Signet/Unstable/Type/TimestampTest.hs
--- a/source/library/Signet/Unstable/Type/TimestampTest.hs
+++ b/source/library/Signet/Unstable/Type/TimestampTest.hs
@@ -1,12 +1,14 @@
 module Signet.Unstable.Type.TimestampTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Data.Time as Time
 import qualified Signet.Unstable.Exception.InvalidTimestamp as InvalidTimestamp
+import qualified Signet.Unstable.Extra.Either as Either
 import qualified Signet.Unstable.Type.Test as Test
 import qualified Signet.Unstable.Type.Timestamp as Timestamp
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Timestamp" $ do
   Test.describe test "parse" $ do
     Test.it test "fails with invalid timestamp format" $ do
@@ -17,12 +19,10 @@
     Test.it test "succeeds with valid timestamp format" $ do
       let byteString = Ascii.pack "1617235200"
       let result = Timestamp.parse byteString
-      case result of
-        Right timestamp -> do
-          let utcTime = Timestamp.unwrap timestamp
-          let expectedTime = Time.UTCTime (Time.fromGregorian 2021 4 1) 0
-          Test.assertEq test utcTime expectedTime
-        Left _ -> fail "Expected Right but got Left"
+      timestamp <- Either.throw result
+      let utcTime = Timestamp.unwrap timestamp
+      let expectedTime = Time.UTCTime (Time.fromGregorian 2021 4 1) 0
+      Test.assertEq test utcTime expectedTime
 
   Test.describe test "render" $ do
     Test.it test "returns the correct ByteString representation" $ do
diff --git a/source/library/Signet/Unstable/Type/ToleranceTest.hs b/source/library/Signet/Unstable/Type/ToleranceTest.hs
--- a/source/library/Signet/Unstable/Type/ToleranceTest.hs
+++ b/source/library/Signet/Unstable/Type/ToleranceTest.hs
@@ -6,7 +6,7 @@
 import qualified Signet.Unstable.Type.Timestamp as Timestamp
 import qualified Signet.Unstable.Type.Tolerance as Tolerance
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Applicative io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Tolerance" $ do
   Test.describe test "check" $ do
     Test.it test "succeeds when timestamp is within tolerance" $ do
diff --git a/source/library/Signet/Unstable/Type/UnknownSignature.hs b/source/library/Signet/Unstable/Type/UnknownSignature.hs
deleted file mode 100644
--- a/source/library/Signet/Unstable/Type/UnknownSignature.hs
+++ /dev/null
@@ -1,10 +0,0 @@
-module Signet.Unstable.Type.UnknownSignature where
-
-import qualified Data.ByteString as ByteString
-
-newtype UnknownSignature
-  = MkUnknownSignature ByteString.ByteString
-  deriving (Eq, Show)
-
-unwrap :: UnknownSignature -> ByteString.ByteString
-unwrap (MkUnknownSignature byteString) = byteString
diff --git a/source/library/Signet/Unstable/Type/UnknownSignatureTest.hs b/source/library/Signet/Unstable/Type/UnknownSignatureTest.hs
deleted file mode 100644
--- a/source/library/Signet/Unstable/Type/UnknownSignatureTest.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Signet.Unstable.Type.UnknownSignatureTest where
-
-import qualified Signet.Unstable.Type.Test as Test
-
-spec :: (Monad tree) => Test.Test tree -> tree ()
-spec test = Test.describe test "Signet.Unstable.Type.UnknownSignature" $ do
-  pure ()
diff --git a/source/library/Signet/Unstable/Type/VerifierTest.hs b/source/library/Signet/Unstable/Type/VerifierTest.hs
--- a/source/library/Signet/Unstable/Type/VerifierTest.hs
+++ b/source/library/Signet/Unstable/Type/VerifierTest.hs
@@ -1,5 +1,6 @@
 module Signet.Unstable.Type.VerifierTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Signet.Unstable.Exception.InvalidVerifier as InvalidVerifier
 import qualified Signet.Unstable.Exception.VerificationException as VerificationException
@@ -14,7 +15,7 @@
 import qualified Signet.Unstable.Type.Test as Test
 import qualified Signet.Unstable.Type.Verifier as Verifier
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable.Type.Verifier" $ do
   Test.describe test "parse" $ do
     Test.it test "succeeds with a valid public key" $ do
@@ -51,7 +52,7 @@
       message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"
       (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="
       let actual = Verifier.verify verifier message signatures
-      Right signature <- Either.throw . Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ=="
+      signature <- Either.throw =<< Either.throw (Signature.parse $ Ascii.pack "v1a,CV1O+PvrwXM42OMUX+tmm6bA3cS0tgLp0qo3YKuu0MGmBrsUhA0MHXF11HsEUJtPfTKs80WE7WUKVt9TueLDCQ==")
       Test.assertEq test actual (Right signature)
 
     Test.it test "fails with an invalid asymmetric signature" $ do
@@ -66,7 +67,7 @@
       message <- Either.throw . Message.parse $ Ascii.pack "i.0.Hello, world!"
       (_, signatures) <- Either.throw . Signatures.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="
       let actual = Verifier.verify verifier message signatures
-      Right signature <- Either.throw . Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="
+      signature <- Either.throw =<< Either.throw (Signature.parse $ Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw=")
       Test.assertEq test actual (Right signature)
 
     Test.it test "fails with an invalid symmetric signature" $ do
diff --git a/source/library/Signet/UnstableTest.hs b/source/library/Signet/UnstableTest.hs
--- a/source/library/Signet/UnstableTest.hs
+++ b/source/library/Signet/UnstableTest.hs
@@ -1,5 +1,6 @@
 module Signet.UnstableTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Data.ByteString.Char8 as Ascii
 import qualified Data.Time as Time
 import qualified Signet.Unstable as Signet
@@ -14,7 +15,7 @@
 import qualified Signet.Unstable.Type.Tolerance as Tolerance
 import qualified Signet.Unstable.Type.Verifier as Verifier
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadThrow io, Monad tree) => Test.Test io tree -> tree ()
 spec test = Test.describe test "Signet.Unstable" $ do
   Test.describe test "verifyWebhookText" $ do
     pure ()
@@ -34,7 +35,7 @@
       let byteString = Ascii.pack "v1,IywpE5NXy+JdAScgR7j5Pt59GjmazD7iJuVsQoRZFyw="
       (_, signatures) <- Either.throw $ Signatures.parse byteString
       let result = Signet.verifyWebhookWith tolerance now verifier message signatures
-      Right signature <- Either.throw $ Signature.parse byteString
+      signature <- Either.throw =<< Either.throw (Signature.parse byteString)
       Test.assertEq test result (Right signature)
 
     Test.it test "fails with an invalid timestamp" $ do
diff --git a/source/library/SignetTest.hs b/source/library/SignetTest.hs
--- a/source/library/SignetTest.hs
+++ b/source/library/SignetTest.hs
@@ -1,5 +1,6 @@
 module SignetTest where
 
+import qualified Control.Monad.Catch as Exception
 import qualified Signet.Unstable.Exception.InvalidAsymmetricSignatureTest
 import qualified Signet.Unstable.Exception.InvalidIdTest
 import qualified Signet.Unstable.Exception.InvalidMessageTest
@@ -13,6 +14,7 @@
 import qualified Signet.Unstable.Exception.InvalidVerifierTest
 import qualified Signet.Unstable.Exception.SignetExceptionTest
 import qualified Signet.Unstable.Exception.ToleranceExceptionTest
+import qualified Signet.Unstable.Exception.UnknownSignatureTest
 import qualified Signet.Unstable.Exception.VerificationExceptionTest
 import qualified Signet.Unstable.Extra.EitherTest
 import qualified Signet.Unstable.Extra.HttpTest
@@ -31,11 +33,10 @@
 import qualified Signet.Unstable.Type.Test as Test
 import qualified Signet.Unstable.Type.TimestampTest
 import qualified Signet.Unstable.Type.ToleranceTest
-import qualified Signet.Unstable.Type.UnknownSignatureTest
 import qualified Signet.Unstable.Type.VerifierTest
 import qualified Signet.UnstableTest
 
-spec :: (Monad tree) => Test.Test tree -> tree ()
+spec :: (Exception.MonadCatch io, Monad tree) => Test.Test io tree -> tree ()
 spec test = do
   Signet.Unstable.Exception.InvalidAsymmetricSignatureTest.spec test
   Signet.Unstable.Exception.InvalidIdTest.spec test
@@ -67,6 +68,6 @@
   Signet.Unstable.Type.SymmetricSignatureTest.spec test
   Signet.Unstable.Type.TimestampTest.spec test
   Signet.Unstable.Type.ToleranceTest.spec test
-  Signet.Unstable.Type.UnknownSignatureTest.spec test
+  Signet.Unstable.Exception.UnknownSignatureTest.spec test
   Signet.Unstable.Type.VerifierTest.spec test
   Signet.UnstableTest.spec test
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -10,7 +10,7 @@
 testTree :: Tasty.TestTree
 testTree = Tasty.testGroup "signet" . Writer.execWriter $ SignetTest.spec tasty
 
-tasty :: Test.Test (Writer.Writer [Tasty.TestTree])
+tasty :: Test.Test IO (Writer.Writer [Tasty.TestTree])
 tasty =
   Test.MkTest
     { Test.assertFailure = Unit.assertFailure,
