diff --git a/derive-has-field.cabal b/derive-has-field.cabal
--- a/derive-has-field.cabal
+++ b/derive-has-field.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.35.2.
+-- This file has been generated from package.yaml by hpack version 0.38.2.
 --
 -- see: https://github.com/sol/hpack
 
 name:           derive-has-field
-version:        0.1.2.0
+version:        0.1.2.1
 synopsis:       Derive HasField instances with Template Haskell
 description:    A Template Haskell function to derive HasField instances to utilize OverloadedRecordDot more effectively.
 category:       Template Haskell
@@ -40,16 +40,18 @@
       TypeApplications
   build-depends:
       base >=4.7 && <5
-    , template-haskell >=2.5 && <2.20
-    , th-abstraction >0.4 && <0.7
+    , template-haskell >=2.5 && <2.24
+    , th-abstraction >0.4 && <0.8
   default-language: Haskell2010
 
 test-suite derive-has-field-test
   type: exitcode-stdio-1.0
   main-is: Spec.hs
   other-modules:
+      DeriveHasFieldCompilerErrorsSpec
       DeriveHasFieldSpec
       Import
+      Import.Types
       Paths_derive_has_field
   hs-source-dirs:
       test
@@ -63,7 +65,8 @@
   build-depends:
       base >=4.7 && <5
     , derive-has-field
-    , hspec >=2.10.10 && <2.11
-    , template-haskell >=2.5 && <2.20
-    , th-abstraction >0.4 && <0.7
+    , hspec >=2.10.10 && <2.12
+    , template-haskell >=2.5 && <2.24
+    , th-abstraction >0.4 && <0.8
+    , th-test-utils ==1.2.*
   default-language: Haskell2010
diff --git a/test/DeriveHasFieldCompilerErrorsSpec.hs b/test/DeriveHasFieldCompilerErrorsSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/DeriveHasFieldCompilerErrorsSpec.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module DeriveHasFieldCompilerErrorsSpec (spec) where
+
+import DeriveHasField qualified
+import Import.Types
+import Language.Haskell.TH (Dec)
+import Language.Haskell.TH.TestUtils
+import Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "deriveHasFieldWithPrefix" $ do
+    it "must modify fields when a prefix is requested" $ do
+      result :: Either String [Dec] <-
+        $( do
+            let state =
+                  QState
+                    { mode = MockQ
+                    , knownNames = [("F", ''F)]
+                    , reifyInfo = $(loadNames [''F])
+                    }
+            let result =
+                  tryTestQ
+                    state
+                    (DeriveHasField.deriveHasFieldWithPrefix "world" ''F)
+            [|pure result|]
+         )
+      result
+        `shouldBe` Left "deriveHasField: the given prefix `world` doesn't match the data constructor names"
+
+  describe "deriveHasField" $ do
+    it "must be a record with fields" $ do
+      result :: Either String [Dec] <-
+        $( do
+            let state =
+                  QState
+                    { mode = MockQ
+                    , knownNames = [("C", ''C)]
+                    , reifyInfo = $(loadNames [''C])
+                    }
+            let result =
+                  tryTestQ
+                    state
+                    (DeriveHasField.deriveHasField ''C)
+            [|pure result|]
+         )
+      result
+        `shouldBe` Left "deriveHasField: only supports data constructors with field names"
+
+    it "should not be a sum of products" $ do
+      result :: Either String [Dec] <-
+        $( do
+            let state =
+                  QState
+                    { mode = MockQ
+                    , knownNames = [("D", ''D)]
+                    , reifyInfo = $(loadNames [''D])
+                    }
+            let result =
+                  tryTestQ
+                    state
+                    (DeriveHasField.deriveHasField ''D)
+            [|pure result|]
+         )
+      result
+        `shouldBe` Left "deriveHasField: only supports product types with a single data constructor"
+
+    it "must share the same string representation when using deriveHasField" $ do
+      result :: Either String [Dec] <-
+        $( do
+            let state =
+                  QState
+                    { mode = MockQ
+                    , knownNames = [("A", ''A)]
+                    , reifyInfo = $(loadNames [''A])
+                    }
+            let result =
+                  tryTestQ
+                    state
+                    (DeriveHasField.deriveHasField ''A)
+            [|pure result|]
+         )
+      result
+        `shouldBe` Left "deriveHasField: type and data constructor must have the same string representation"
+
+    it "must match record field prefix when using deriveHasField" $ do
+      result :: Either String [Dec] <-
+        $( do
+            let state =
+                  QState
+                    { mode = MockQ
+                    , knownNames = [("X", ''X)]
+                    , reifyInfo = $(loadNames [''X])
+                    }
+            let result =
+                  tryTestQ
+                    state
+                    (DeriveHasField.deriveHasField ''X)
+            [|pure result|]
+         )
+      result
+        `shouldBe` Left "deriveHasField: the assumed prefix `x` doesn't match the data constructor names"
diff --git a/test/Import/Types.hs b/test/Import/Types.hs
new file mode 100644
--- /dev/null
+++ b/test/Import/Types.hs
@@ -0,0 +1,11 @@
+module Import.Types where
+
+newtype X = X {yHello :: String}
+
+newtype A = B {b :: String}
+
+newtype C = C String
+
+data D = D {d :: String} | E {e :: String}
+
+newtype F = F {fHello :: String}
