diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,10 @@
 Changelog for Safe
 
+0.3.21, released 2024-01-18
+    #34, mark headErr/tailErr as Partial
+0.3.20, released 2024-01-14
+    #34, add headErr, tailErr
+    #33, avoid using head/tail to avoid x-partial
 0.3.19, released 2020-05-24
     #30, undeprecate maximumDef and friends, fold*1Def
 0.3.18, released 2019-12-04
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Neil Mitchell 2007-2020.
+Copyright Neil Mitchell 2007-2024.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Safe [![Hackage version](https://img.shields.io/hackage/v/safe.svg?label=Hackage)](https://hackage.haskell.org/package/safe) [![Stackage version](https://www.stackage.org/package/safe/badge/nightly?label=Stackage)](https://www.stackage.org/package/safe) [![Build status](https://img.shields.io/travis/ndmitchell/safe/master.svg?label=Build)](https://travis-ci.org/ndmitchell/safe)
+# Safe [![Hackage version](https://img.shields.io/hackage/v/safe.svg?label=Hackage)](https://hackage.haskell.org/package/safe) [![Stackage version](https://www.stackage.org/package/safe/badge/nightly?label=Stackage)](https://www.stackage.org/package/safe) [![Build status](https://img.shields.io/github/actions/workflow/status/ndmitchell/safe/ci.yml?branch=master)](https://github.com/ndmitchell/safe/actions)
 
 A library wrapping `Prelude`/`Data.List` functions that can throw exceptions, such as `head` and `!!`. Each unsafe function has up to four variants, e.g. with `tail`:
 
diff --git a/Safe.hs b/Safe.hs
--- a/Safe.hs
+++ b/Safe.hs
@@ -1,11 +1,16 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ConstraintKinds  #-}
+
+{-# OPTIONS_GHC -Wno-x-partial -Wno-unrecognised-warning-flags #-}
+
 {- |
 A module wrapping @Prelude@/@Data.List@ functions that can throw exceptions, such as @head@ and @!!@.
-Each unsafe function has up to four variants, e.g. with @tail@:
+Each unsafe function has up to five variants, e.g. with @tail@:
 
-* @'tail' :: [a] -> [a]@, raises an error on @tail []@.
+* @'tail' :: [a] -> [a]@, raises an error on @tail []@, as provided by 'Prelude'.
 
+* @'tailErr' :: [a] -> [a]@, alias for @tail@ that doesn't trigger an @x-partial@ warning and does raise errors.
+
 * @'tailMay' :: [a] -> /Maybe/ [a]@, turns errors into @Nothing@.
 
 * @'tailDef' :: /[a]/ -> [a] -> [a]@, takes a default to return on errors.
@@ -23,6 +28,8 @@
 module Safe(
     -- * New functions
     abort, at, lookupJust, findJust, elemIndexJust, findIndexJust,
+    -- * Partial functions
+    tailErr, headErr,
     -- * Safe wrappers
     tailMay, tailDef, tailNote, tailSafe,
     initMay, initDef, initNote, initSafe,
@@ -94,11 +101,28 @@
 ---------------------------------------------------------------------
 -- WRAPPERS
 
+-- | Identical to 'tail', namely that fails on an empty list.
+--   Useful to avoid the @x-partial@ warning introduced in GHC 9.8.
+--
+-- > tailErr [] = error "Prelude.tail: empty list"
+-- > tailErr [1,2,3] = [2,3]
+tailErr :: Partial => [a] -> [a]
+tailErr = tail
+
+-- | Identical to 'head', namely that fails on an empty list.
+--   Useful to avoid the @x-partial@ warning introduced in GHC 9.8.
+--
+-- > headErr [] = error "Prelude.head: empty list"
+-- > headErr [1,2,3] = 1
+headErr :: Partial => [a] -> a
+headErr = head
+
 -- |
 -- > tailMay [] = Nothing
 -- > tailMay [1,3,4] = Just [3,4]
 tailMay :: [a] -> Maybe [a]
-tailMay = liftMay null tail
+tailMay [] = Nothing
+tailMay (_:xs) = Just xs
 
 -- |
 -- > tailDef [12] [] = [12]
@@ -134,7 +158,7 @@
 
 
 headMay, lastMay :: [a] -> Maybe a
-headMay = liftMay null head
+headMay = listToMaybe
 lastMay = liftMay null last
 
 headDef, lastDef :: a -> [a] -> a
diff --git a/Safe/Exact.hs b/Safe/Exact.hs
--- a/Safe/Exact.hs
+++ b/Safe/Exact.hs
@@ -96,7 +96,7 @@
 -- >   | n >= 0 && n <= length xs = drop n xs
 -- >   | otherwise                = error "some message"
 dropExact :: Partial => Int -> [a] -> [a]
-dropExact i xs = withFrozenCallStack $ splitAtExact_ (addNote "" "dropExact") id (flip const) i xs
+dropExact i xs = withFrozenCallStack $ splitAtExact_ (addNote "" "dropExact") id (\_ x -> x) i xs
 
 -- |
 -- > splitAtExact n xs =
@@ -116,10 +116,10 @@
 takeExactDef def = fromMaybe def .^ takeExactMay
 
 dropExactNote :: Partial => String -> Int -> [a] -> [a]
-dropExactNote note i xs = withFrozenCallStack $ splitAtExact_ (addNote note "dropExactNote") id (flip const) i xs
+dropExactNote note i xs = withFrozenCallStack $ splitAtExact_ (addNote note "dropExactNote") id (\_ x -> x) i xs
 
 dropExactMay :: Int -> [a] -> Maybe [a]
-dropExactMay = splitAtExact_ (const Nothing) Just (flip const)
+dropExactMay = splitAtExact_ (const Nothing) Just (\_ x -> x)
 
 dropExactDef :: [a] -> Int -> [a] -> [a]
 dropExactDef def = fromMaybe def .^ dropExactMay
diff --git a/safe.cabal b/safe.cabal
--- a/safe.cabal
+++ b/safe.cabal
@@ -1,17 +1,17 @@
-cabal-version:  >= 1.18
+cabal-version:  1.18
 build-type:     Simple
 name:           safe
-version:        0.3.19
+version:        0.3.21
 license:        BSD3
 license-file:   LICENSE
 category:       Unclassified
 author:         Neil Mitchell <ndmitchell@gmail.com>
 maintainer:     Neil Mitchell <ndmitchell@gmail.com>
-copyright:      Neil Mitchell 2007-2020
+copyright:      Neil Mitchell 2007-2024
 homepage:       https://github.com/ndmitchell/safe#readme
 synopsis:       Library of safe (exception free) functions
 bug-reports:    https://github.com/ndmitchell/safe/issues
-tested-with:    GHC==8.10.1, GHC==8.8.3, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2
+tested-with:    GHC==9.8, GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8
 description:
     A library wrapping @Prelude@/@Data.List@ functions that can throw exceptions, such as @head@ and @!!@.
     Each unsafe function has up to four variants, e.g. with @tail@:
