diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
 
 ## Unreleased
 
+## 0.21.0.0 - 2025-12-23 (Happy Holidays!)
+* NB: The next version of `ghc-events` will likely drop support for versions of GHC before 9.2. Please open a ticket if this is an issue for you.
+* Support GHC-9.12 ([#113](https://github.com/haskell/ghc-events/pull/113))
+* Drop dependency on array ([#114](https://github.com/haskell/ghc-events/pull/114))
+* Canonical Monoid instance for MaxVars ([#115](https://github.com/haskell/ghc-events/pull/115))
+* Support containers-0.8 ([#117](https://github.com/haskell/ghc-events/pull/117))
+* Export `step` from GHC.RTS.Events.Analysis ([#118](https://github.com/haskell/ghc-events/pull/118))
+* Relax event length assertions ([#122](https://github.com/haskell/ghc-events/pull/122))
+* Support GHC-9.14 ([#124](https://github.com/haskell/ghc-events/pull/124))
 
 ## 0.20.0.0 - 2024-11-25
 
diff --git a/ghc-events.cabal b/ghc-events.cabal
--- a/ghc-events.cabal
+++ b/ghc-events.cabal
@@ -1,6 +1,6 @@
 cabal-version:    2.4
 name:             ghc-events
-version:          0.20.0.0
+version:          0.21.0.0
 synopsis:         Library and tool for parsing .eventlog files from GHC
 description:      Parses .eventlog files emitted by GHC 8.0.2 and later.
                   Includes the ghc-events tool permitting, in particular,
@@ -29,10 +29,12 @@
                   GHC == 8.10.7
                   GHC == 9.0.2
                   GHC == 9.2.4
-                  GHC == 9.4.2
-                  GHC == 9.6.1
-                  GHC == 9.8.1
-                  GHC == 9.10.1
+                  GHC == 9.4.8
+                  GHC == 9.6.7
+                  GHC == 9.8.4
+                  GHC == 9.10.3
+                  GHC == 9.12.2
+                  GHC == 9.14.1
 extra-source-files: include/EventLogFormat.h
                     test/*.eventlog
                     test/*.reference
@@ -55,11 +57,10 @@
 
 library
   import:           default
-  build-depends:    base       >= 4.7 && < 4.21,
-                    containers >= 0.5 && < 0.8,
+  build-depends:    base       >= 4.7 && < 4.23,
+                    containers >= 0.5 && < 0.9,
                     binary     >= 0.7 && < 0.11,
                     bytestring >= 0.10.4 && < 0.13,
-                    array      >= 0.2 && < 0.6,
                     text       >= 0.11.2.3 && < 2.2,
                     vector     >= 0.7 && < 0.14
   exposed-modules:  GHC.RTS.Events,
diff --git a/src/GHC/RTS/EventParserUtils.hs b/src/GHC/RTS/EventParserUtils.hs
--- a/src/GHC/RTS/EventParserUtils.hs
+++ b/src/GHC/RTS/EventParserUtils.hs
@@ -12,26 +12,27 @@
         skip,
     ) where
 
-import Data.Array
 import Data.Binary
 import Data.Binary.Get ()
 import Data.Binary.Put ()
 import Data.IntMap (IntMap)
 import Data.List
 import Data.Text (Text)
+import Data.Vector (Vector)
 import qualified Data.Binary.Get as G
 import qualified Data.ByteString.Char8 as B8
 import qualified Data.IntMap as M
 import qualified Data.Text.Encoding as TE
 import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Encoding as TLE
+import qualified Data.Vector as Vec
 
 #define EVENTLOG_CONSTANTS_ONLY
 #include "EventLogFormat.h"
 
 import GHC.RTS.EventTypes
 
-newtype EventParsers = EventParsers (Array Int (Get EventInfo))
+newtype EventParsers = EventParsers (Vector (Get EventInfo))
 
 getString :: Integral a => a -> Get String
 getString len = do
@@ -123,10 +124,10 @@
 
 mkEventTypeParsers :: IntMap EventType
                    -> [EventParser EventInfo]
-                   -> Array Int (Get EventInfo)
+                   -> Vector (Get EventInfo)
 mkEventTypeParsers etypes event_parsers
- = accumArray (flip const) undefined (0, max_event_num)
-    [ (num, parser num) | num <- [0..max_event_num] ]
+ = Vec.fromList
+    [ parser num | num <- [0..max_event_num] ]
   where
     max_event_num = maximum (M.keys etypes)
     undeclared_etype num = fail ("undeclared event type: " ++ show num)
diff --git a/src/GHC/RTS/Events/Analysis.hs b/src/GHC/RTS/Events/Analysis.hs
--- a/src/GHC/RTS/Events/Analysis.hs
+++ b/src/GHC/RTS/Events/Analysis.hs
@@ -1,5 +1,6 @@
 module GHC.RTS.Events.Analysis
   ( Machine (..)
+  , step
   , validate
   , validates
   , simulate
diff --git a/src/GHC/RTS/Events/Binary.hs b/src/GHC/RTS/Events/Binary.hs
--- a/src/GHC/RTS/Events/Binary.hs
+++ b/src/GHC/RTS/Events/Binary.hs
@@ -33,7 +33,7 @@
 import Data.Int
 import Prelude hiding (gcd, rem, id)
 
-import Data.Array
+import Data.Vector ((!))
 import Data.Binary
 import Data.Binary.Put
 import qualified Data.Binary.Get as G
@@ -657,7 +657,7 @@
     heapProfRetainerFilter <- getTextNul
     heapProfBiographyFilter <- getTextNul
     assert
-      (fromIntegral payloadLen == sum
+      (fromIntegral payloadLen >= sum
         [ 1 -- heapProfId
         , 8 -- heapProfSamplingPeriod
         , 4 -- heapProfBreakdown
@@ -679,7 +679,7 @@
     heapProfSrcLoc <- getTextNul
     heapProfFlags <- get
     assert
-      (fromIntegral payloadLen == sum
+      (fromIntegral payloadLen >= sum
         [ 4 -- heapProfCostCentreId
         , textByteLen heapProfLabel
         , textByteLen heapProfModule
@@ -699,7 +699,7 @@
     itModule <- getTextNul
     itSrcLoc <- getTextNul
     assert
-      (fromIntegral payloadLen == sum
+      (fromIntegral payloadLen >= sum
         [ 8 -- itInfo
         , textByteLen itTableName
         , textByteLen itClosureDescText
@@ -727,7 +727,7 @@
     heapProfStackDepth <- get
     heapProfStack <- VU.replicateM (fromIntegral heapProfStackDepth) get
     assert
-      ((fromIntegral payloadLen :: Int) == sum
+      ((fromIntegral payloadLen :: Int) >= sum
         [ 1 -- heapProfId
         , 8 -- heapProfResidency
         , 1 -- heapProfStackDepth
@@ -741,7 +741,7 @@
     heapProfResidency <- get
     heapProfLabel <- getTextNul
     assert
-      (fromIntegral payloadLen == sum
+      (fromIntegral payloadLen >= sum
         [ 1 -- heapProfId
         , 8 -- heapProfResidency
         , textByteLen heapProfLabel
@@ -762,7 +762,7 @@
     profStackDepth <- get
     profCcsStack <- VU.replicateM (fromIntegral profStackDepth) get
     assert
-      ((fromIntegral payloadLen :: Int) == sum
+      ((fromIntegral payloadLen :: Int) >= sum
         [ 4
         , 8 -- ticks
         , 1 -- stack depth
@@ -825,7 +825,7 @@
     tickyCtrDefName    <- getTextNul
     tickyCtrInfoTbl    <- optionalGet payloadLen start_bytes (0 :: Word64) get
     tickyCtrJsonDesc   <- optionalGet payloadLen start_bytes Nothing (Just <$> getTextNul)
-    assert (fromIntegral payloadLen ==
+    assert (fromIntegral payloadLen >=
       (sum
         [ 8 -- tickyCtrDefId
         , 2 -- tickyCtrDefArity
diff --git a/src/GHC/RTS/Events/Merge.hs b/src/GHC/RTS/Events/Merge.hs
--- a/src/GHC/RTS/Events/Merge.hs
+++ b/src/GHC/RTS/Events/Merge.hs
@@ -49,15 +49,22 @@
                        , mthread :: !ThreadId }
 -- TODO introduce parallel RTS process and machine var.s
 
+combineMaxVars :: MaxVars -> MaxVars -> MaxVars
+combineMaxVars (MaxVars a b c) (MaxVars x y z) =
+      MaxVars (max a x) (b + y) (max c z)
+
 #if MIN_VERSION_base(4,11,0)
 instance Semigroup MaxVars where
-    (<>) = mappend
+    (<>) = combineMaxVars
 #endif
 
 instance Monoid MaxVars where
     mempty  = MaxVars 0 0 0
-    mappend (MaxVars a b c) (MaxVars x y z) =
-      MaxVars (max a x) (b + y) (max c z)
+#if MIN_VERSION_base(4,11,0)
+    mappend = (<>)
+#else
+    mappend = combineMaxVars
+#endif
     -- avoid space leaks:
     mconcat = foldl' mappend mempty
 
