diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
 # Change Log
 All notable changes to this project will be documented in this file.
 This project adheres to [Package Versioning Policy](https://wiki.haskell.org/Package_versioning_policy).
+## [0.4.0.1] - 2020-03-22
+
+### Fixed
+- MonadFail usage
+
+## [0.4.0.0] - 2020-02-08
+
+### Fixed
+- Compatibility with GHC 8.8
+
 ## [0.3.2.8] - 2019-06-13
 
 ### Fixed
diff --git a/Data/Bson.hs b/Data/Bson.hs
--- a/Data/Bson.hs
+++ b/Data/Bson.hs
@@ -25,16 +25,19 @@
   ObjectId(..), timestamp, genObjectId, showHexLen
 ) where
 
-import Prelude hiding (lookup)
+import Prelude hiding (fail, lookup)
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative ((<$>))
 #endif
+#if MIN_VERSION_base(4, 9, 0)
+import Control.Monad.Fail (MonadFail(fail))
+#endif
 import Control.Monad (foldM)
 import Data.Bits (shift, (.|.))
 import Data.Int (Int32, Int64)
 import Data.IORef (IORef, newIORef, atomicModifyIORef)
 import Data.List (find, findIndex)
-import Data.Maybe (maybeToList, mapMaybe, fromMaybe)
+import Data.Maybe (maybeToList, mapMaybe, fromJust, fromMaybe)
 import Data.Time.Clock (UTCTime)
 import Data.Time.Clock.POSIX (POSIXTime, posixSecondsToUTCTime,
                               utcTimeToPOSIXSeconds, getPOSIXTime)
@@ -89,18 +92,18 @@
 doc !? l = foldM (flip lookup) doc (init chunks) >>= lookup (last chunks)
   where chunks = T.split (== '.') l
 
-look :: (Monad m) => Label -> Document -> m Value
+look :: (MonadFail m) => Label -> Document -> m Value
 -- ^ Value of field in document, or fail (Nothing) if field not found
 look k doc = maybe notFound (return . value) (find ((k ==) . label) doc)
   where notFound = fail $ "expected " ++ show k ++ " in " ++ show doc
 
-lookup :: (Val v, Monad m) => Label -> Document -> m v
+lookup :: (Val v, MonadFail m) => Label -> Document -> m v
 -- ^ Lookup value of field in document and cast to expected type. Fail (Nothing) if field not found or value not of expected type.
 lookup k doc = cast =<< look k doc
 
 valueAt :: Label -> Document -> Value
 -- ^ Value of field in document. Error if missing.
-valueAt k = runIdentity . look k
+valueAt k = fromJust . look k
 
 at :: (Val v) => Label -> Document -> v
 -- ^ Typed value of field in document. Error if missing or wrong type.
@@ -199,7 +202,7 @@
 
 -- * Value conversion
 
-cast :: (Val a, Monad m) => Value -> m a
+cast :: (Val a, MonadFail m) => Value -> m a
 -- ^ Convert Value to expected type, or fail (Nothing) if not of that type
 cast v = maybe notType return castingResult
   where
@@ -210,7 +213,7 @@
 
 typed :: (Val a) => Value -> a
 -- ^ Convert Value to expected type. Error if not that type.
-typed = runIdentity . cast
+typed = fromJust . cast
 
 typeOfVal :: Value -> TypeRep
 -- ^ Type of typed value
diff --git a/bson.cabal b/bson.cabal
--- a/bson.cabal
+++ b/bson.cabal
@@ -1,5 +1,5 @@
 Name:          bson
-Version:       0.3.2.8
+Version:       0.4.0.1
 Synopsis:      BSON documents are JSON-like objects with a standard binary
                encoding.
 Description:   A BSON Document is an untyped (dynamically type-checked) record.
@@ -28,7 +28,7 @@
   manual: False
 
 Library
-  Build-depends:      base < 5
+  Build-depends:      base >= 4.9.0.0 && < 5
                     , time
                     , bytestring
                     , binary >= 0.5 && < 0.9
diff --git a/tests/Data/Bson/Tests.hs b/tests/Data/Bson/Tests.hs
--- a/tests/Data/Bson/Tests.hs
+++ b/tests/Data/Bson/Tests.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances, OverloadedStrings, TypeSynonymInstances #-}
 
 module Data.Bson.Tests
     ( tests
@@ -7,6 +7,9 @@
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative ((<$>), (<*>))
 #endif
+#if MIN_VERSION_base(4,9,0)
+import Control.Monad.Fail(MonadFail(..))
+#endif
 import Data.Int (Int32, Int64)
 import Data.Time.Calendar (Day(ModifiedJulianDay))
 import Data.Time.Clock.POSIX (POSIXTime)
@@ -16,7 +19,7 @@
 import Data.Text (Text)
 import Test.Framework (Test, testGroup)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
-import Test.QuickCheck (Arbitrary(..), elements, oneof)
+import Test.QuickCheck (Arbitrary(..), elements, oneof, Property, (===))
 import qualified Data.Text as T
 
 import Data.Bson (Val(cast', val), ObjectId(..), MinMaxKey(..), MongoStamp(..),
@@ -106,6 +109,17 @@
     Nothing -> False
     Just a' -> a == a'
 
+#if MIN_VERSION_base(4,9,0)
+instance MonadFail (Either String) where
+   fail = Left
+
+testLookMonadFail :: Property
+testLookMonadFail =
+   (Bson.look "key" [] :: Either String Value)
+      -- This is as opposed to an exception thrown from Prelude.fail:
+      === Left "expected \"key\" in []"
+#endif
+
 tests :: Test
 tests = testGroup "Data.Bson.Tests"
     [ testProperty "Val Bool"        (testVal :: Bool -> Bool)
@@ -131,4 +145,8 @@
     , testProperty "Val Binary"      (testVal :: Binary -> Bool)
     -- , testProperty "Val Document"    (testVal :: Document -> Bool)
     , testProperty "Val Text"        (testVal :: Text -> Bool)
+
+#if MIN_VERSION_base(4,9,0)
+    , testProperty "'look' uses MonadFail.fail" testLookMonadFail
+#endif
     ]
