diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Revision history for wai-handler-hal
 
+## 0.5.0.0 -- 2025-12-14
+
+- Breaking change: Replace unsafe `decodeUtf8` with `decodeUtf8Lenient`
+  for header and body decoding. Invalid UTF-8 sequences are now replaced
+  with Unicode replacement characters (U+FFFD) instead of throwing exceptions
+  from purely functional code.
+
 ## 0.4.0.2 -- 2025-08-14
 
 - Union single and multi-value query parameters and headers when
diff --git a/src/Network/Wai/Handler/Hal.hs b/src/Network/Wai/Handler/Hal.hs
--- a/src/Network/Wai/Handler/Hal.hs
+++ b/src/Network/Wai/Handler/Hal.hs
@@ -329,7 +329,7 @@
 getHeader :: HeaderName -> HalRequest.ProxyRequest a -> Maybe ByteString
 getHeader h =
   fmap Text.encodeUtf8
-    . HashMap.lookup (CI.map Text.decodeUtf8 h)
+    . HashMap.lookup (CI.map Text.decodeUtf8Lenient h)
     . HalRequest.headers
 
 -- | Convert a WAI 'Wai.Response' into a hal
@@ -369,11 +369,11 @@
 createProxyBody :: Options -> MediaType -> ByteString -> HalResponse.ProxyBody
 createProxyBody opts contentType body =
   HalResponse.ProxyBody
-    { HalResponse.contentType = Text.decodeUtf8 $ renderHeader contentType,
+    { HalResponse.contentType = Text.decodeUtf8Lenient $ renderHeader contentType,
       HalResponse.serialized =
         if isBase64Encoded
-          then Text.decodeUtf8 $ Base64.encode body
-          else Text.decodeUtf8 body,
+          then Text.decodeUtf8Lenient $ Base64.encode body
+          else Text.decodeUtf8Lenient body,
       HalResponse.isBase64Encoded
     }
   where
@@ -385,8 +385,8 @@
   where
     addHeader r (hName, hValue) =
       HalResponse.addHeader
-        (Text.decodeUtf8 $ CI.original hName)
-        (Text.decodeUtf8 hValue)
+        (Text.decodeUtf8Lenient $ CI.original hName)
+        (Text.decodeUtf8Lenient hValue)
         r
 
 -- | Try to find the content-type of a response, given the response
diff --git a/wai-handler-hal.cabal b/wai-handler-hal.cabal
--- a/wai-handler-hal.cabal
+++ b/wai-handler-hal.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.2
 name:               wai-handler-hal
-version:            0.4.0.2
+version:            0.5.0.0
 synopsis:           Wrap WAI applications to run on AWS Lambda
 description:
   This library provides a function 'Network.Wai.Handler.Hal.run' to
@@ -28,16 +28,10 @@
   test/golden/WaiRequest.txt
 
 tested-with:
-  GHC ==8.6.5
-   || ==8.8.4
-   || ==8.10.7
-   || ==9.0.2
-   || ==9.2.4
-   || ==9.4.5
-   || ==9.6.6
-   || ==9.8.2
-   || ==9.10.1
-   || ==9.12.1
+  GHC ==9.6.7
+   || ==9.8.4
+   || ==9.10.3
+   || ==9.12.2
 
 common opts
   default-language: Haskell2010
@@ -58,7 +52,7 @@
     , http-media            ^>=0.8.1.1
     , http-types            ^>=0.12.3
     , network               >=3.2.3.0   && <3.3
-    , text                  ^>=1.2.3    || ^>=2.0  || ^>=2.1
+    , text                  ^>=2.0  || ^>=2.1
     , unordered-containers  ^>=0.2.10.0
     , vault                 ^>=0.3.1.0
     , wai                   ^>=3.2.2
