diff --git a/enumerator.cabal b/enumerator.cabal
--- a/enumerator.cabal
+++ b/enumerator.cabal
@@ -1,5 +1,5 @@
 name: enumerator
-version: 0.4.11
+version: 0.4.12
 synopsis: Reliable, high-performance processing with left-fold enumerators
 license: MIT
 license-file: license.txt
diff --git a/hs/Data/Enumerator.hs b/hs/Data/Enumerator.hs
--- a/hs/Data/Enumerator.hs
+++ b/hs/Data/Enumerator.hs
@@ -329,16 +329,45 @@
 -- all errors to be represented by 'Exc.SomeException', libraries with
 -- varying error types can be easily composed.
 --
+-- WARNING: after a few rounds of "catchError doesn't work because X", this
+-- function has grown into a horrible monster. I have no concept of what
+-- unexpected behaviors lurk in its dark crevices. Users are strongly advised
+-- to wrap all uses of @catchError@ with an appropriate @isolate@, such as
+-- @Data.Enumerator.List.isolate@ or @Data.Enumerator.Binary.isolate@, which
+-- will handle input framing even in the face of unexpected errors.
+--
+-- Within the error handler, it is difficult or impossible to know how much
+-- input the original iteratee has consumed.
+--
 -- Since: 0.1.1
 
 catchError :: Monad m
            => Iteratee a m b
            -> (Exc.SomeException -> Iteratee a m b)
            -> Iteratee a m b
-catchError iter h = iter >>== step where
-	step (Yield b as) = yield b as
-	step (Error err) = h err
-	step (Continue k) = continue (\s -> k s >>== step)
+catchError i h = continue (wrap i) where
+	wrap iter EOF = Iteratee $ do
+		res <- run iter
+		case res of
+			Left err -> runIteratee (enumEOF $$ h err)
+			Right b -> return (Yield b EOF)
+	
+	wrap iter stream = Iteratee $ do
+		step <- runIteratee iter
+		case step of
+			Yield b as -> return (Yield b (mappend as stream))
+			Error err -> do
+				step' <- runIteratee (h err)
+				case step' of
+					Yield b _ -> return (Yield b stream)
+					Error err' -> return (Error err')
+					Continue k -> runIteratee (k stream)
+			Continue k -> do
+				step' <- runIteratee (k stream)
+				case step' of
+					Yield b as -> return (Yield b as)
+					Error err -> runIteratee (h err)
+					Continue k' -> return (Continue (wrap (continue k')))
 
 
 infixl 1 >>==
diff --git a/src/api-docs.anansi b/src/api-docs.anansi
--- a/src/api-docs.anansi
+++ b/src/api-docs.anansi
@@ -254,6 +254,16 @@
 -- all errors to be represented by 'Exc.SomeException', libraries with
 -- varying error types can be easily composed.
 --
+-- WARNING: after a few rounds of "catchError doesn't work because X", this
+-- function has grown into a horrible monster. I have no concept of what
+-- unexpected behaviors lurk in its dark crevices. Users are strongly advised
+-- to wrap all uses of @catchError@ with an appropriate @isolate@, such as
+-- @Data.Enumerator.List.isolate@ or @Data.Enumerator.Binary.isolate@, which
+-- will handle input framing even in the face of unexpected errors.
+--
+-- Within the error handler, it is difficult or impossible to know how much
+-- input the original iteratee has consumed.
+--
 -- Since: 0.1.1
 :
 
diff --git a/src/primitives.anansi b/src/primitives.anansi
--- a/src/primitives.anansi
+++ b/src/primitives.anansi
@@ -111,8 +111,27 @@
            => Iteratee a m b
            -> (Exc.SomeException -> Iteratee a m b)
            -> Iteratee a m b
-catchError iter h = iter >>== step where
-	step (Yield b as) = yield b as
-	step (Error err) = h err
-	step (Continue k) = continue (\s -> k s >>== step)
+catchError i h = continue (wrap i) where
+	wrap iter EOF = Iteratee $ do
+		res <- run iter
+		case res of
+			Left err -> runIteratee (enumEOF $$ h err)
+			Right b -> return (Yield b EOF)
+	
+	wrap iter stream = Iteratee $ do
+		step <- runIteratee iter
+		case step of
+			Yield b as -> return (Yield b (mappend as stream))
+			Error err -> do
+				step' <- runIteratee (h err)
+				case step' of
+					Yield b _ -> return (Yield b stream)
+					Error err' -> return (Error err')
+					Continue k -> runIteratee (k stream)
+			Continue k -> do
+				step' <- runIteratee (k stream)
+				case step' of
+					Yield b as -> return (Yield b as)
+					Error err -> runIteratee (h err)
+					Continue k' -> return (Continue (wrap (continue k')))
 :
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -673,6 +673,7 @@
 test_Other = F.testGroup "Other"
 	[ test_Sequence
 	, test_joinE
+	, test_CatchError_NotDivergent
 	]
 
 test_Sequence :: F.Test
@@ -692,6 +693,17 @@
 		expected = map (* 10) xs
 		
 		iter = (E.joinE (E.enumList 1 xs) (EL.map (* 10))) $$ EL.consume
+
+test_CatchError_NotDivergent :: F.Test
+test_CatchError_NotDivergent = testProperty "catchError not divergent" test where
+	test = case runIdentity (E.run (E.enumList 1 [] $$ iter)) of
+		Left err -> Exc.fromException err == Just (Exc.ErrorCall "require: Unexpected EOF")
+		Right _ -> False
+	iter = E.catchError
+		(do
+			EL.head
+			E.throwError (Exc.ErrorCall "error"))
+		(\_ -> EL.require 1)
 
 -- misc
 
