diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+# ChangeLog for shakespeare
+
+### 2.0.21
+
+* Support for GHC 8.8
 
 ### 2.0.20
 * Restore allowing GHC to detect changes to i18n message files in GHC >= 8.4.
diff --git a/Text/Hamlet/Parse.hs b/Text/Hamlet/Parse.hs
--- a/Text/Hamlet/Parse.hs
+++ b/Text/Hamlet/Parse.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE TemplateHaskell #-}
@@ -37,7 +38,10 @@
     return = Ok
     Error s >>= _ = Error s
     Ok v >>= f = f v
+#if MIN_VERSION_base(4,13,0)
+instance MonadFail Result where
     fail = Error
+#endif
 instance Functor Result where
     fmap = liftM
 instance Applicative Result where
diff --git a/Text/Internal/Css.hs b/Text/Internal/Css.hs
--- a/Text/Internal/Css.hs
+++ b/Text/Internal/Css.hs
@@ -123,7 +123,7 @@
                    -> String
                    -> [(Deref, VarType)]
 cssUsedIdentifiers toi2b parseBlocks s' =
-    concat $ runIdentity $ mapM (getVars scope0) contents
+    concat $ either error id $ mapM (getVars scope0) contents
   where
     s = if toi2b then i2b s' else s'
     a = either (error . show) id $ parse parseBlocks s s
@@ -289,7 +289,7 @@
     c VTUrlParam = [|CDUrlParam|]
     c VTMixin = [|CDMixin|]
 
-getVars :: Monad m => [(String, String)] -> Content -> m [(Deref, VarType)]
+getVars :: [(String, String)] -> Content -> Either String [(Deref, VarType)]
 getVars _ ContentRaw{} = return []
 getVars scope (ContentVar d) =
     case lookupD d scope of
@@ -298,15 +298,15 @@
 getVars scope (ContentUrl d) =
     case lookupD d scope of
         Nothing -> return [(d, VTUrl)]
-        Just s -> fail $ "Expected URL for " ++ s
+        Just s -> Left $ "Expected URL for " ++ s
 getVars scope (ContentUrlParam d) =
     case lookupD d scope of
         Nothing -> return [(d, VTUrlParam)]
-        Just s -> fail $ "Expected URLParam for " ++ s
+        Just s -> Left $ "Expected URLParam for " ++ s
 getVars scope (ContentMixin d) =
     case lookupD d scope of
         Nothing -> return [(d, VTMixin)]
-        Just s -> fail $ "Expected Mixin for " ++ s
+        Just s -> Left $ "Expected Mixin for " ++ s
 
 lookupD :: Deref -> [(String, b)] -> Maybe String
 lookupD (DerefIdent (Ident s)) scope =
diff --git a/shakespeare.cabal b/shakespeare.cabal
--- a/shakespeare.cabal
+++ b/shakespeare.cabal
@@ -1,5 +1,5 @@
 name:            shakespeare
-version:         2.0.20
+version:         2.0.21
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
