diff --git a/Data/Conduit/Cereal.hs b/Data/Conduit/Cereal.hs
--- a/Data/Conduit/Cereal.hs
+++ b/Data/Conduit/Cereal.hs
@@ -1,54 +1,45 @@
-{-# LANGUAGE DeriveDataTypeable #-}
-
--- | Turn a 'Get' into a 'Sink' and a 'Put' into a 'Source'
-
-module Data.Conduit.Cereal (sinkGet, conduitGet, sourcePut) where
-
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Lazy as LBS
-import qualified Data.Conduit as C
-import           Data.Conduit.List (sourceList)
-import           Data.Serialize hiding (get, put)
-import           Data.Typeable
-import           Control.Exception
-
-data GetException = GetException String
-     deriving (Show, Typeable)
-
-instance Exception GetException
-
--- | Convert a 'Get' into a 'Sink'. The 'Get' will be streamed bytes until it returns 'Done' or 'Fail'.
---
--- If 'Get' succeed it will return the data read and unconsumed part of the input stream.
--- If the 'Get' fails it will return message describing the error. 
-sinkGet :: Monad m => Get output -> C.Sink BS.ByteString m (Either String output)
-sinkGet get = consume (runGetPartial get) BS.empty
-  where push f input
-          | BS.null input = C.NeedInput (push f) (close f)
-          | otherwise = consume f input
-        consume f s = case f s of
-          Fail msg   -> C.Done (streamToMaybe s) (Left msg)
-          Partial f' -> C.NeedInput (push f') (close f')
-          Done r s'  -> C.Done (streamToMaybe s') (Right r)
-        close f = let Fail r = f BS.empty in C.Done Nothing (Left r)
-
--- | Run a 'Get' repeatedly on the input stream, producing an output stream of whatever the 'Get' outputs.
-conduitGet :: Monad m => Get output -> C.Conduit BS.ByteString m output
-conduitGet get = consume (runGetPartial get) BS.empty BS.empty
-  where push f b input
-          | BS.null input = C.NeedInput (push f b) (C.Done (streamToMaybe b) ())
-          | otherwise = consume f b input
-        consume f b s = case f s of
-          Fail msg -> throw $ GetException msg
-          Partial f' -> C.NeedInput (push f' consumed) $ C.Done (streamToMaybe consumed) ()
-          Done r s' -> C.HaveOutput (push (runGetPartial get) BS.empty s') (return ()) r
-          where consumed = BS.concat [b, s]
-
-streamToMaybe :: BS.ByteString -> Maybe BS.ByteString
-streamToMaybe s = if BS.null s
-                    then Nothing
-                    else Just s
-
--- | Convert a 'Put' into a 'Source'. Runs in constant memory.
-sourcePut :: Monad m => Put -> C.Source m BS.ByteString
-sourcePut put = sourceList $ LBS.toChunks $ runPutLazy put
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- | Turn a 'Get' into a 'Sink' and a 'Put' into a 'Source'
+-- These functions are built upno the Data.Conduit.Cereal.Internal functions with default
+-- implementations of 'ErrorHandler' and 'TerminationHandler'
+--
+-- The default 'ErrorHandler' and 'TerminationHandler' both throw a 'GetException'.
+
+module Data.Conduit.Cereal (GetException, sinkGet, conduitGet, sourcePut) where
+
+import           Control.Monad.Exception
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.Conduit as C
+import           Data.Conduit.Cereal.Internal
+import           Data.Conduit.List (sourceList)
+import           Data.Serialize hiding (get, put)
+import           Data.Typeable
+
+data GetException = GetException String
+  deriving (Show, Typeable)
+
+instance Exception GetException
+
+-- | Run a 'Get' repeatedly on the input stream, producing an output stream of whatever the 'Get' outputs.
+conduitGet :: MonadException m => Get output -> C.Conduit BS.ByteString m output
+conduitGet = mkConduitGet errorHandler 
+  where errorHandler msg _ = pipeError $ GetException msg 
+
+-- | Convert a 'Get' into a 'Sink'. The 'Get' will be streamed bytes until it returns 'Done' or 'Fail'.
+--
+-- If 'Get' succeed it will return the data read and unconsumed part of the input stream.
+-- If the 'Get' fails due to deserialization error or early termination of the input stream it raise an error.
+sinkGet :: MonadException m => Get r -> C.Sink BS.ByteString m r
+sinkGet = mkSinkGet errorHandler terminationHandler 
+  where errorHandler msg _ = pipeError $ GetException msg 
+        terminationHandler f _ = let Fail msg = f BS.empty in pipeError $ GetException msg 
+
+pipeError :: (MonadException m, Exception e) => e -> C.Pipe i o m r
+pipeError e = C.PipeM (throw e) undefined 
+
+-- | Convert a 'Put' into a 'Source'. Runs in constant memory.
+sourcePut :: Monad m => Put -> C.Source m BS.ByteString
+sourcePut put = sourceList $ LBS.toChunks $ runPutLazy put
diff --git a/Test/CerealConduit.hs b/Test/CerealConduit.hs
--- a/Test/CerealConduit.hs
+++ b/Test/CerealConduit.hs
@@ -1,83 +1,199 @@
-module Test.CerealConduit (tests) where
+{-# LANGUAGE FlexibleContexts, RankNTypes #-}
 
+module Test.CerealConduit where
+
 import Control.Monad.Identity
+import Control.Monad.Exception
+import Control.Monad.Error
+import Control.Monad.Trans.Maybe
 import Test.HUnit
 import qualified Data.Conduit as C
 import Data.Conduit.Cereal
-import Data.Conduit.List
+import Data.Conduit.Cereal.Internal 
+import Data.Conduit.List as CL
 import Data.Serialize
 import qualified Data.ByteString as BS
-import Test.Framework.Providers.HUnit
+--import Test.Framework.Providers.HUnit
 import System.Exit
 import Data.Word
+import qualified Data.List as L
+import Prelude hiding (take)
 
+-- For the sake of these tests, all SomeExceptions are equal
+instance Eq SomeException where
+  a == b = True
+
+twoItemGet :: Get Word8
+twoItemGet = do
+  x <- getWord8
+  y <- getWord8
+  return $ x + y
+
 sinktest1 :: Test
 sinktest1 = TestCase (assertEqual "Handles starting with empty bytestring"
   (Right 1)
-  (runIdentity $ (sourceList [BS.pack [], BS.pack [1]]) C.$$ (sinkGet getWord8)))
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [], BS.pack [1]]) C.$$ (sinkGet getWord8)))
 
 sinktest2 :: Test
 sinktest2 = TestCase (assertEqual "Handles empty bytestring in middle"
   (Right [1, 3])
-  (runIdentity $ (sourceList [BS.pack [1], BS.pack [], BS.pack [3]]) C.$$ (sinkGet (do
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1], BS.pack [], BS.pack [3]]) C.$$ (sinkGet (do
     x <- getWord8
     y <- getWord8
     return [x, y]))))
 
 sinktest3 :: Test
 sinktest3 = TestCase (assertBool "Handles no data"
-  (case (runIdentity $ (sourceList []) C.$$ (sinkGet getWord8)) of
+  (case runIdentity $ runExceptionT $ (sourceList []) C.$$ (sinkGet getWord8) of
     Right _ -> False
     Left _ -> True))
 
 sinktest4 :: Test
 sinktest4 = TestCase (assertEqual "Consumes no data"
   (Right ())
-  (runIdentity $ (sourceList [BS.pack [1]]) C.$$ (sinkGet $ return ())))
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1]]) C.$$ (sinkGet $ return ())))
 
-twoItemGet :: Get Word8
-twoItemGet = do
-  x <- getWord8
-  y <- getWord8
-  return $ x + y
+sinktest5 :: Test
+sinktest5 = TestCase (assertEqual "Empty list"
+  (Right ())
+  (runIdentity $ runExceptionT $ (sourceList []) C.$$ (sinkGet $ return ())))
 
+sinktest6 :: Test
+sinktest6 = TestCase (assertEqual "Leftover input works"
+  (Right (1, BS.pack [2, 3, 4, 5]))
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2, 3], BS.pack [4, 5]]) C.$$ (do
+    output <- sinkGet getWord8
+    output' <- CL.consume
+    return (output, BS.concat output'))))
+
+-- Current sink implementation will terminate the pipe in case of error. 
+-- One may need non-terminating version like one defined below to get access to Leftovers
+
+sinkGetMaybe :: Monad m => Get output -> C.Sink BS.ByteString m (Maybe output)
+sinkGetMaybe = mkSinkGet errorHandler terminationHandler . fmap Just
+  where errorHandler     msg s = C.Done s Nothing
+        terminationHandler f s = C.Done s Nothing
+
+sinktest7 :: Test
+sinktest7 = TestCase (assertBool "Leftover input with failure works"
+  (case runIdentity $ do
+     (sourceList [BS.pack [1, 2]]) C.$$ (do
+       output <- sinkGetMaybe (getWord8 >> fail "" :: Get Word8)
+       output' <- CL.consume
+       return (output, BS.concat output')) of
+     (Nothing, bs) -> bs == BS.pack [1, 2]
+     otherwise -> False))
+
 conduittest1 :: Test
 conduittest1 = TestCase (assertEqual "Handles starting with empty bytestring"
-  []
-  (runIdentity $ (sourceList [BS.pack [], BS.pack [1]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [], BS.pack [1]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
 conduittest2 :: Test
 conduittest2 = TestCase (assertEqual "Works when the get is split across items"
-  [3]
-  (runIdentity $ (sourceList [BS.pack [1], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [3])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
 conduittest3 :: Test
 conduittest3 = TestCase (assertEqual "Works when empty bytestring in middle of get"
-  [3]
-  (runIdentity $ (sourceList [BS.pack [1], BS.pack [], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [3])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1], BS.pack [], BS.pack [2]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
 conduittest4 :: Test
 conduittest4 = TestCase (assertEqual "Works when empty bytestring at end of get"
-  [3, 7]
-  (runIdentity $ (sourceList [BS.pack [1, 2], BS.pack [], BS.pack [3, 4]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [3])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2], BS.pack []]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
 conduittest5 :: Test
 conduittest5 = TestCase (assertEqual "Works when multiple gets are in an item"
-  [3, 7]
-  (runIdentity $ (sourceList [BS.pack [1, 2, 3, 4]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [3, 7])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2, 3, 4]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
 conduittest6 :: Test
 conduittest6 = TestCase (assertEqual "Works with leftovers"
-  [3]
-  (runIdentity $ (sourceList [BS.pack [1, 2, 3]]) C.$= conduitGet twoItemGet C.$$ consume))
+  (Right [3])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2, 3]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
 
-sinktests = TestList [sinktest1, sinktest2, sinktest3, sinktest4]
+conduittest7 :: Test
+conduittest7 = let c = 10 in TestCase (assertEqual "Works with infinite lists"
+  (Right $ L.replicate c ())
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2, 3]]) C.$= conduitGet (return ()) C.$$ take c))
 
-conduittests = TestList [conduittest1, conduittest2, conduittest3, conduittest4, conduittest5, conduittest6]
+conduittest8 :: Test
+conduittest8 = let c = 10 in TestCase (assertEqual "Works with empty source and infinite lists"
+  (Right $ L.replicate c ())
+  (runIdentity $ runExceptionT $ (sourceList []) C.$= conduitGet (return ()) C.$$ take c))
 
+conduittest9 :: Test
+conduittest9 = let c = 10 in TestCase (assertEqual "Works with two well-placed items"
+  (Right [3, 7])
+  (runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2], BS.pack [3, 4]]) C.$= conduitGet twoItemGet C.$$ CL.consume))
+
+conduittest10 :: Test
+conduittest10 = TestCase (assertBool "Failure works"
+  (case runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2], BS.pack [3, 4]]) C.$= conduitGet (getWord8 >> fail "omfg") C.$$ CL.consume of
+    Left _ -> True
+    Right _ -> False))
+
+conduittest11 :: Test
+conduittest11 = TestCase (assertBool "Immediate failure works"
+  (case runIdentity $ runExceptionT $ (sourceList [BS.pack [1, 2], BS.pack [3, 4]]) C.$= conduitGet (fail "omfg") C.$$ CL.consume of
+    Left _ -> True
+    Right _ -> False))
+
+conduittest12 :: Test
+conduittest12 = TestCase (assertBool "Immediate failure with empty input works"
+  (case runIdentity $ runExceptionT $ (sourceList []) C.$= conduitGet (fail "omfg") C.$$ CL.consume of
+    Left _ -> True
+    Right _ -> False))
+
+{-
+-- This test CAN'T work because of the type of HaveOutput.
+conduittest13 :: Test
+conduittest13 = TestCase (assertEqual "Leftover success conduit input works"
+  ([12], BS.pack [3, 4, 5])
+  (runIdentity $ (sourceList [BS.pack [10, 2, 3], BS.pack [4, 5]]) C.$$ (do
+    output <- (conduitGet twoItemGet) C.=$ (CL.take 1)
+    output' <- CL.consume
+    return (output, BS.concat output'))))
+-}
+
+conduittest14 :: Test
+conduittest14 = TestCase (assertEqual "Leftover failure conduit input works"
+  (Right ([], BS.singleton 1))
+  (runIdentity $ runExceptionT $ (sourceList [BS.singleton 1]) C.$$ (do
+    output <- (conduitGet twoItemGet) C.=$ (CL.take 1)
+    output' <- CL.consume
+    return (output, BS.concat output'))))
+
+sinktests = TestList [ sinktest1
+                     , sinktest2
+                     , sinktest3
+                     , sinktest4
+                     , sinktest5
+                     , sinktest6
+                     , sinktest7
+                     ]
+
+conduittests = TestList [ conduittest1
+                        , conduittest2
+                        , conduittest3
+                        , conduittest4
+                        , conduittest5
+                        , conduittest6
+                        , conduittest7
+                        , conduittest8
+                        , conduittest9
+                        , conduittest10
+                        , conduittest11
+                        , conduittest12
+                        --, conduittest13
+                        , conduittest14
+                        ]
+
 hunittests = TestList [sinktests, conduittests]
 
-tests = hUnitTestToTests hunittests
+--tests = hUnitTestToTests hunittests
 
 main = do
   counts <- runTestTT hunittests
diff --git a/cereal-conduit.cabal b/cereal-conduit.cabal
--- a/cereal-conduit.cabal
+++ b/cereal-conduit.cabal
@@ -1,5 +1,5 @@
 name:            cereal-conduit
-version:         0.0.5
+version:         0.0.6
 license:         BSD3
 license-file:    LICENSE
 author:          Myles C. Maxfield <myles.maxfield@gmail.com>
@@ -18,6 +18,8 @@
                  , cereal   >= 0.3.1.0
                  , mtl
                  , bytestring
+                 , void
+                 , exception-transformers
     exposed-modules: Data.Conduit.Cereal
     ghc-options:     -Wall
 
@@ -31,6 +33,7 @@
                  , bytestring
                  , test-framework-hunit
                  , HUnit
+                 , transformers
 
 source-repository head
   type:     git
