diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # bz2
 
+## 1.0.1.0
+
+  * Add `decompressErr`
+
 ## 1.0.0.3
 
   * Fix bug decompressing partial data
diff --git a/bz2.cabal b/bz2.cabal
--- a/bz2.cabal
+++ b/bz2.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               bz2
-version:            1.0.0.3
+version:            1.0.1.0
 license:            BSD3
 license-file:       LICENSE
 copyright:          Copyright: (c) 2020 Vanessa McHale
@@ -99,8 +99,7 @@
         tasty-golden -any,
         tasty-hunit -any,
         deepseq -any,
-        directory -any,
-        mmap -any
+        directory -any
 
     if impl(ghc >=8.0)
         ghc-options:
diff --git a/src/Codec/Compression/BZip.hs b/src/Codec/Compression/BZip.hs
--- a/src/Codec/Compression/BZip.hs
+++ b/src/Codec/Compression/BZip.hs
@@ -5,6 +5,7 @@
                                 compress
                               , compressWith
                               , decompress
+                              , decompressErr
                               -- * Errors
                               , BZError (..)
                               -- * Miscellany
diff --git a/src/Codec/Compression/BZip/Unpack.chs b/src/Codec/Compression/BZip/Unpack.chs
--- a/src/Codec/Compression/BZip/Unpack.chs
+++ b/src/Codec/Compression/BZip/Unpack.chs
@@ -1,12 +1,14 @@
 {-# LANGUAGE TupleSections #-}
 
 module Codec.Compression.BZip.Unpack ( decompress
+                                     , decompressErr
                                      ) where
 
 import Codec.Compression.BZip.Foreign.Common
 import Codec.Compression.BZip.Foreign.Decompress
 import Codec.Compression.BZip.Common
 import Control.Applicative
+import Control.Exception (evaluate, throw, try)
 import Control.Monad (when)
 import Control.Monad.ST.Lazy as LazyST
 import Control.Monad.ST.Lazy.Unsafe as LazyST
@@ -16,9 +18,16 @@
 import Data.Maybe (isNothing)
 import Foreign.ForeignPtr (newForeignPtr, castForeignPtr, ForeignPtr, mallocForeignPtrBytes, withForeignPtr)
 import Foreign.Ptr (Ptr, castPtr, nullPtr)
+import System.IO.Unsafe (unsafePerformIO)
 
 #include <bzlib.h>
 
+-- | Return an error rather than throwing an exception.
+--
+-- @since 1.0.1.0
+decompressErr :: BSL.ByteString -> Either BZError BSL.ByteString
+decompressErr = unsafePerformIO . try . evaluate . decompress
+
 -- | Don't use this on pathological input; it may not be secure
 --
 -- This does not handle nested streams
@@ -78,7 +87,7 @@
             if ret == BzStreamEnd
                 then pure (newBSAp [])
                 else if null bs' && isNothing keepAlive && bufSz == szOut
-                    then error "Out of input"
+                    then throw BzUnexpectedEof
                     else newBSAp <$> fillBuf pForeign keepAlive bs'' step' bufOutForeign
 
         keepBytesAlive :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString])
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -3,10 +3,10 @@
 import           Codec.Compression.BZip
 import           Control.Concurrent     (forkIO, newEmptyMVar, putMVar, readMVar)
 import           Control.DeepSeq        (deepseq)
+import           Control.Exception      (evaluate, try)
 import qualified Data.ByteString.Lazy   as BSL
 import           System.Directory       (doesFileExist)
 import           System.FilePath        ((-<.>))
-import           System.IO.MMap         (mmapFileByteStringLazy)
 import           Test.Tasty
 import           Test.Tasty.Golden
 import           Test.Tasty.HUnit
@@ -21,11 +21,6 @@
 forceBSL :: BSL.ByteString -> IO ()
 forceBSL bsl = last (BSL.toChunks bsl) `seq` (pure ())
 
-testDecompressMMap :: FilePath -> TestTree
-testDecompressMMap fp = testCase ("Decompress mmap " ++ fp) $ do
-    res <- decompress <$> mmapFileByteStringLazy fp Nothing
-    assertBool "Doesn't crash" (last (BSL.toChunks res) `seq` True)
-
 testCompress :: FilePath -> TestTree
 testCompress fp = testCase ("Roundtrip " ++ fp) $ do
     contents <- BSL.readFile fp
@@ -55,7 +50,8 @@
 testNoLoop = testCase "Decompress partial" $ do
     contents <- BSL.readFile "test/data/sample2.bz2"
     let partial = BSL.take (64 * 1024) contents
-    forceBSL (decompress partial) *> assertFailure "Throws exception"
+        res = decompressErr partial
+    res @?= Left BzUnexpectedEof
 
 main :: IO ()
 main = do
@@ -66,7 +62,7 @@
                 else id
 
     defaultMain $
-        testGroup "bz2" (go [testDecompression, testCompression, testMMap])
+        testGroup "bz2" (go [testNoLoop, testDecompression, testCompression])
 
     where
         compressedFiles = [ "test/data/sample1.bz2"
@@ -80,5 +76,3 @@
             , testCompress "test/data/sample2.ref"
             , testCompress "test/data/sample3.ref"
             ]
-        testMMap = testGroup "MMap"
-            (testDecompressMMap <$> compressedFiles)
