diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # ChangeLog for conduit
 
+## 1.3.1.2
+
+* More eagerly emit groups in `chunksOf` [#427](https://github.com/snoyberg/conduit/pull/427)
+
 ## 1.3.1.1
 
 * Use lower-case imports (better for cross-compilation) [#408](https://github.com/snoyberg/conduit/pull/408)
diff --git a/conduit.cabal b/conduit.cabal
--- a/conduit.cabal
+++ b/conduit.cabal
@@ -1,5 +1,5 @@
 Name:                conduit
-Version:             1.3.1.1
+Version:             1.3.1.2
 Synopsis:            Streaming data processing library.
 description:
     `conduit` is a solution to the streaming data problem, allowing for production,
diff --git a/src/Data/Conduit/List.hs b/src/Data/Conduit/List.hs
--- a/src/Data/Conduit/List.hs
+++ b/src/Data/Conduit/List.hs
@@ -88,6 +88,9 @@
     , maybe
     , (<=)
     , (>)
+    , error
+    , (++)
+    , show
     )
 import Data.Monoid (Monoid, mempty, mappend)
 import qualified Data.Foldable as F
@@ -684,17 +687,14 @@
 --
 -- Since 1.2.9
 chunksOf :: Monad m => Int -> ConduitT a [a] m ()
-chunksOf n =
-    start
+chunksOf n = if n > 0 then loop n id else error $ "chunksOf size must be positive (given " ++ show n ++ ")"
   where
-    start = await >>= maybe (return ()) (\x -> loop n (x:))
-
-    loop !count rest =
-        await >>= maybe (yield (rest [])) go
-      where
-        go y
-            | count > 1 = loop (count - 1) (rest . (y:))
-            | otherwise = yield (rest []) >> loop n (y:)
+    loop 0 rest = yield (rest []) >> loop n id
+    loop count rest = await >>= \ma -> case ma of
+      Nothing -> case rest [] of
+        [] -> return ()
+        nonempty -> yield nonempty
+      Just a -> loop (count - 1) (rest . (a :))
 
 -- | Grouping input according to an equality function.
 --
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -5,6 +5,7 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 import Test.Hspec
 import Test.Hspec.QuickCheck (prop)
+import Test.QuickCheck (getPositive)
 import Test.QuickCheck.Monadic (assert, monadicIO, run)
 
 import Data.Conduit (runConduit, (.|), ConduitT, runConduitPure, runConduitRes)
@@ -13,7 +14,7 @@
 import qualified Data.Conduit.Internal as CI
 import qualified Data.Conduit.List as CL
 import Data.Typeable (Typeable)
-import Control.Exception (throw)
+import Control.Exception (throw, evaluate)
 import Control.Monad.Trans.Resource (runResourceT)
 import Control.Monad.Trans.Maybe (MaybeT (MaybeT))
 import Control.Monad.State.Strict (modify)
@@ -241,11 +242,18 @@
                     .| CL.fold (+) 0
             x `shouldBe` 2 * sum [1..10 :: Int]
 
-        prop "chunksOf" $ equivToList
-            (DLS.chunksOf 5 :: [Int]->[[Int]]) (CL.chunksOf 5)
+        prop "chunksOf" $ \(positive, xs) ->
+            let p = getPositive positive
+                conduit = CL.sourceList xs .| CL.chunksOf p .| CL.consume
+            in DLS.chunksOf p (xs :: [Int]) == runConduitPure conduit
 
-        prop "chunksOf (negative)" $ equivToList
-            (map (:[]) :: [Int]->[[Int]]) (CL.chunksOf (-5))
+        it "chunksOf (zero)" $
+            let conduit = return () .| CL.chunksOf 0 .| CL.consume
+            in evaluate (runConduitPure conduit) `shouldThrow` anyException
+
+        it "chunksOf (negative)" $
+            let conduit = return () .| CL.chunksOf (-5) .| CL.consume
+            in evaluate (runConduitPure conduit) `shouldThrow` anyException
 
         it "groupBy" $ do
             let input = [1::Int, 1, 2, 3, 3, 3, 4, 5, 5]
