diff --git a/Data/OpenWitness/Exception.hs b/Data/OpenWitness/Exception.hs
new file mode 100644
--- /dev/null
+++ b/Data/OpenWitness/Exception.hs
@@ -0,0 +1,39 @@
+module Data.OpenWitness.Exception
+(
+	Exn, unsafeExnFromString, throw, catch
+) where
+{
+	import Data.OpenWitness;
+	import Data.Witness;
+	import Data.Maybe;
+	import Data.Typeable;
+	import Control.Exception (throwDyn,catchDyn);
+	import Prelude(IO,String);
+
+	-- | A key to match exceptions. The type variable is the data the exception carries.
+	;
+	type Exn = IOWitness;
+
+	newtype ExnException = MkExnException (Any Exn);
+	
+	-- | In the absence of open witness declarations, an unsafe hack to generate 'Exn' exception keys.
+	-- This is safe if you use a different string each time (and 'hashString' doesn't collide), and if @e@ is a single type.
+	;
+	unsafeExnFromString :: String -> Exn e;
+	unsafeExnFromString = unsafeIOWitnessFromString;
+	
+	instance Typeable ExnException where
+	{
+		typeOf _ = mkTyConApp (mkTyCon "Data.OpenWitness.Exception.ExnException") [];
+	};
+	
+	throw :: Exn e -> e -> a;
+	throw exn e = throwDyn (MkExnException (MkAny exn e));
+	
+	catch :: IO a -> Exn e -> (e -> IO a) -> IO a;
+	catch foo exn catcher = catchDyn foo (\ex@(MkExnException cell) -> case matchAny exn cell of
+	{
+		Just e -> catcher e;
+		_ -> throwDyn ex;
+	});
+}
diff --git a/open-witness.cabal b/open-witness.cabal
--- a/open-witness.cabal
+++ b/open-witness.cabal
@@ -1,5 +1,5 @@
 name:			open-witness
-version:		0.1
+version:		0.1.1
 license:		BSD3
 license-file:	LICENSE
 author:			Ashley Yakeley <ashley@semantic.org>
@@ -28,4 +28,5 @@
 	Data.OpenWitness.Typeable
 	Data.OpenWitness.Typeable.Rep
 	Data.OpenWitness.Dynamic
+	Data.OpenWitness.Exception
 other-modules:
