diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,23 @@
 and this project adheres to the
 [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## 0.5.1.0 - 2026-07-02
+
+* Fix a regression on unsupported operating systems.
+
+## 0.5.0.0 - 2026-06-22
+
+* Fix a regression on Linux operating systems, whereby `xdg-open` would not
+  return until the browser was closed.
+* Replace utility `openBrowserWithExitCode` with `openBrowserWithException`.
+
+## 0.4.0.0 - 2025-04-02
+
+* On Unix-like operating systems, use Haskell to silence the opening
+  application or script, rather than the `sh` shell on Linux and BSD.
+* Add utility `openBrowserWithExitCode`, to help with debugging failure.
+* Improve Haddock documentation.
+
 ## 0.3.0.1 - 2025-03-17
 
 * On Windows, remove unnecessary dependency on `process`.
@@ -31,8 +48,9 @@
 
 * As released by rightfold on Hackage. This entry and prior change log is
   reconstructed.
-* Support GHC versions before GHC 8.0.
-* Add support for 32-bit Windows.
+* Support GHC versions before GHC 8.0, by removing the Byte Order Mark from
+  source files.
+* Add support for 32-bit Windows, by using the `stdcall` calling convention.
 
 ## 0.2.0.0 - 2015-07-31
 
@@ -40,11 +58,13 @@
 
 ## 0.1.4.0 - 2015-07-30
 
-* On Linux, silence `xdg-open`.
+* On Linux and BSD, silence the `xdg-open` script using the `sh` shell.
 
 ## 0.1.3.0 - 2015-07-27
 
-* Add support for BSD and Windows.
+* Add support for BSD, using the `xdg-open` script.
+* Add support for Windows, using the Win32 API and the `ccall` calling
+  convention.
 
 ## 0.1.2.0 - 2015-07-27
 
@@ -52,8 +72,9 @@
 
 ## 0.1.1.0 - 2015-07-27
 
-* Add support for Linux.
+* Add support for Linux, using the `xdg-open` script.
+* On OS X, use the `open` application.
 
 ## 0.1.0.0 - 2015-07-25
 
-* Initial version. Only OS X supported.
+* Initial version. Only OS X supported, using `open location` in an AppleScript.
diff --git a/example/Main.hs b/example/Main.hs
--- a/example/Main.hs
+++ b/example/Main.hs
@@ -4,9 +4,27 @@
   ( main
   ) where
 
-import Web.Browser ( openBrowser )
+import Control.Exception ( Exception (..), SomeException )
+import Web.Browser ( openBrowser, openBrowserWithException )
 
 main :: IO ()
-main = openBrowser "https://haskell.org/" >>= \case
-  True -> putStrLn "The operation succeeded!"
-  False -> putStrLn "The operation failed!"
+main = do
+  openBrowser "https://haskell.org/" >>= \case
+    True -> putStrLn "The operation succeeded!"
+    False -> putStrLn "The operation failed!"
+  blankLine
+  putStrLn "Help with debugging:"
+  putStrLn "Try a good URL:"
+  tryOpenGoodUrl >>= reportResult
+  blankLine
+  putStrLn "Try a bad URL:"
+  tryOpenBadUrl >>= reportResult
+ where
+  tryOpenGoodUrl :: IO (Maybe SomeException)
+  tryOpenGoodUrl = openBrowserWithException "https://haskell.org/"
+  tryOpenBadUrl :: IO (Maybe SomeException)
+  tryOpenBadUrl = openBrowserWithException "example-bad-url"
+  reportResult = \case
+    Just e -> putStrLn $ "Exception: " <> displayException e
+    Nothing -> putStrLn "Nothing to report"
+  blankLine = putStrLn ""
diff --git a/lib/Web/Browser.hs b/lib/Web/Browser.hs
--- a/lib/Web/Browser.hs
+++ b/lib/Web/Browser.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE LambdaCase #-}
+
 {-|
 Module      : Web.Browser
 Description : Open a web browser from Haskell
@@ -11,14 +13,18 @@
 
 module Web.Browser
   ( openBrowser
+    -- * Utilities
+  , openBrowserWithException
   ) where
 
+import           Control.Exception ( Exception (..), SomeException, try)
+import           Data.Maybe ( isNothing )
 import qualified Web.Browser.OS as OS
 
--- | Seeks to open the given item. If the item is a URL or another item
--- associated with a web browser (for example, it represents a local @.html@
--- file), seeks to open it in the user's preferred web browser. Returns whether
--- or not the operation succeeded.
+-- | Seeks to open the given item, silently. If the item is a URL or another
+-- item associated with a web browser (for example, it represents a local
+-- @.html@ file), seeks to open it in the user's preferred web browser. Returns
+-- whether or not the operation succeeded.
 --
 -- No checks are performed on the nature or validity of the given item.
 --
@@ -31,13 +37,28 @@
 --   item that represents a file, equivalent to double-clicking on the file's
 --   icon; and
 --
--- * on Linux, FreeBSD, OpenBSD or NetBSD, the \'xdg-open\' application, if it
---   is on the user's PATH, via \'sh\' to allow the application's output to be
---   silenced.
+-- * on Linux, FreeBSD, OpenBSD or NetBSD, the \'xdg-open\' script, if it
+--   is on the user's PATH.
 --
 -- On other operating systems, the operation always fails.
+--
+-- @since 0.1.0.0
 openBrowser ::
      String
-     -- ^ URL or other item to try to open
+     -- ^ URL or other item to try to open.
   -> IO Bool
-openBrowser = OS.openBrowser
+openBrowser url =
+  isNothing <$> (openBrowserWithException url :: IO (Maybe SomeException))
+
+-- | Exported to help with debugging. As for 'openBrowser' but returns 'Nothing'
+-- or 'Just' an exception.
+--
+-- @since 0.5.0.0
+openBrowserWithException ::
+     Exception e
+  => String
+     -- ^ URL or other item to try to open.
+  -> IO (Maybe e)
+openBrowserWithException url = try (OS.openBrowser url) >>= \case
+  Left e -> pure $ Just e
+  Right () -> pure Nothing
diff --git a/lib/unix-like/common/Utils.hs b/lib/unix-like/common/Utils.hs
deleted file mode 100644
--- a/lib/unix-like/common/Utils.hs
+++ /dev/null
@@ -1,20 +0,0 @@
---------------------------------------------------------------------------------
--- For operating systems that use an application on the PATH to open the URL.
---------------------------------------------------------------------------------
-
-module Utils
-  ( openBrowserWith
-  ) where
-
-import System.Exit ( ExitCode (..) )
-import System.Process ( proc, waitForProcess, withCreateProcess )
-
-openBrowserWith ::
-     String
-     -- ^ Name of relevant executable on the PATH.
-  -> [String]
-     -- ^ Arguments for executable.
-  -> IO Bool
-openBrowserWith cmd args =
-  withCreateProcess (proc cmd args) $ \_ _ _ p ->
-    (== ExitSuccess) <$> waitForProcess p
diff --git a/lib/unix-like/open/Web/Browser/OS.hs b/lib/unix-like/open/Web/Browser/OS.hs
--- a/lib/unix-like/open/Web/Browser/OS.hs
+++ b/lib/unix-like/open/Web/Browser/OS.hs
@@ -7,11 +7,18 @@
   ( openBrowser
   ) where
 
-import Utils ( openBrowserWith )
+import           Control.Monad ( void )
+import           System.Process
+                   ( CreateProcess (..), StdStream (..), createProcess, proc )
 
 -- https://ss64.com/mac/open.html
 openBrowser ::
      String
-     -- ^ URL
-  -> IO Bool
-openBrowser url = openBrowserWith "open" [url]
+     -- ^ URL or other item to try to open.
+  -> IO ()
+openBrowser url = void $ createProcess (proc "open" [url])
+  { std_in = NoStream
+  , std_out = NoStream
+  , std_err = NoStream
+  , close_fds = True
+  }
diff --git a/lib/unix-like/xdg-open/Web/Browser/OS.hs b/lib/unix-like/xdg-open/Web/Browser/OS.hs
--- a/lib/unix-like/xdg-open/Web/Browser/OS.hs
+++ b/lib/unix-like/xdg-open/Web/Browser/OS.hs
@@ -1,31 +1,23 @@
 --------------------------------------------------------------------------------
--- For Unix-like operating systems that provide the xdg-open application on the
--- PATH.
+-- For Unix-like operating systems that provide the xdg-open script on the PATH.
 --------------------------------------------------------------------------------
 
 module Web.Browser.OS
   ( openBrowser
   ) where
 
-import Utils ( openBrowserWith )
+import           Control.Monad ( void )
+import           System.Process
+                   ( CreateProcess (..), StdStream (..), createProcess, proc )
 
 -- https://ss64.com/bash/xdg-open.html
 openBrowser ::
      String
-     -- ^ URL
-  -> IO Bool
-openBrowser url =
-  -- sh -c '...'
-  --
-  -- tells the shell (sh) to execute the given string as a command, and
-  -- the following argument (url) is passed as a positional argument $0.
-  --
-  -- xdg-open "$0" 2>&1 > /dev/null
-  --
-  -- The $0 is expanded and the double quotes ensures it is treated as a single
-  -- argument to xdg-open.
-  --
-  -- 2>&1 redirects standard error to standard output.
-  --
-  -- > /dev/null discards standard output.
-  openBrowserWith "sh" ["-c", "xdg-open \"$0\" 2>&1 > /dev/null", url]
+     -- ^ URL or other item to try to open.
+  -> IO ()
+openBrowser url = void $ createProcess (proc "xdg-open" [url])
+  { std_in = NoStream
+  , std_out = NoStream
+  , std_err = NoStream
+  , close_fds = True
+  }
diff --git a/lib/unsupported-os/Web/Browser/OS.hs b/lib/unsupported-os/Web/Browser/OS.hs
--- a/lib/unsupported-os/Web/Browser/OS.hs
+++ b/lib/unsupported-os/Web/Browser/OS.hs
@@ -8,6 +8,8 @@
 
 openBrowser ::
      String
-     -- ^ URL
-  -> IO Bool
-openBrowser = const (pure False) -- Operation never succeeds
+     -- ^ URL or other item to try to open.
+  -> IO ()
+openBrowser _ =
+  -- Operation never succeeds
+  error "openBrowser: Unsupported operating system."
diff --git a/lib/windows/Web/Browser/OS.hs b/lib/windows/Web/Browser/OS.hs
--- a/lib/windows/Web/Browser/OS.hs
+++ b/lib/windows/Web/Browser/OS.hs
@@ -11,8 +11,11 @@
   ( openBrowser
   ) where
 
-import System.Win32.Types
-         ( HANDLE, HINSTANCE, INT, LPCWSTR, handleToWord, nullPtr, withTString )
+import           Control.Monad ( unless )
+import           System.Win32.Types
+                   ( HANDLE, HINSTANCE, INT, LPCWSTR, handleToWord, nullPtr
+                   , withTString
+                   )
 
 type HWND = HANDLE
 
@@ -26,14 +29,16 @@
 
 openBrowser ::
      String
-     -- ^ URL
-  -> IO Bool
-openBrowser url =
-  withTString "open" $ \openStr ->
-    withTString url $ \urlStr -> exitCodeToBool <$>
+     -- ^ URL or other item to try to open.
+  -> IO ()
+openBrowser url = do
+  hinst <- withTString "open" $ \openStr ->
+    withTString url $ \urlStr ->
       c_ShellExecute nullPtr openStr urlStr nullPtr nullPtr sW_SHOWNORMAL
- where
-  exitCodeToBool hinst = handleToWord hinst > 32
+  let exitcode = fromIntegral (handleToWord hinst) :: Int
+  unless (exitcode > 32) $ error $
+       "openBrowser: ShellExecuteW \"open\" failed with exit code: "
+    <> show exitcode
 
 -- https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew
 foreign import ccall unsafe "windows.h ShellExecuteW"
diff --git a/open-browser.cabal b/open-browser.cabal
--- a/open-browser.cabal
+++ b/open-browser.cabal
@@ -1,86 +1,80 @@
 cabal-version: 1.12
-
--- This file has been generated from package.yaml by hpack version 0.38.0.
---
--- see: https://github.com/sol/hpack
-
-name:           open-browser
-version:        0.3.0.1
-synopsis:       Open a web browser from Haskell
-description:    Open a web browser from Haskell. Windows, macOS, Linux and BSD are supported.
-category:       Web
-homepage:       https://github.com/mpilgrem/open-browser
-bug-reports:    https://github.com/mpilgrem/open-browser/issues
-author:         rightfold
-maintainer:     public@pilgrem.com
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-tested-with:
-    GHC >= 8.4
-extra-source-files:
-    CHANGELOG.md
-    README.md
-    stack.yaml
-    stack.yaml.lock
-
-source-repository head
-  type: git
-  location: https://github.com/mpilgrem/open-browser
-
-flag example
-  description: Build the example application
-  manual: True
-  default: False
-
-library
-  hs-source-dirs:
-      lib
-  exposed-modules:
-      Web.Browser
-  build-depends:
-      base ==4.*
-  default-language: Haskell2010
-  if os(windows)
-    other-modules:
-        Web.Browser.OS
-    hs-source-dirs:
-        lib/windows
-    build-depends:
-        Win32 <3
-  else
-    if os(darwin)
-      other-modules:
-          Utils
-          Web.Browser.OS
-      hs-source-dirs:
-          lib/unix-like/common
-          lib/unix-like/open
-      build-depends:
-          process >=1.4.3.0 && <2
-    else
-      if os(linux) || os(freebsd) || os(openbsd) || os(netbsd)
-        other-modules:
-            Utils
-            Web.Browser.OS
-        hs-source-dirs:
-            lib/unix-like/common
-            lib/unix-like/xdg-open
-        build-depends:
-            process >=1.4.3.0 && <2
-      else
-        other-modules:
-            Web.Browser.OS
-        hs-source-dirs:
-            lib/unsupported-os
-
-executable open-browser-example
-  main-is: Main.hs
-  hs-source-dirs:
-      example
-  build-depends:
-      base ==4.*
-    , open-browser
-  default-language: Haskell2010
-  if !flag(example)
-    buildable: False
+
+-- This file has been generated from package.yaml by hpack version 0.39.6.
+--
+-- see: https://github.com/sol/hpack
+
+name:           open-browser
+version:        0.5.1.0
+synopsis:       Open a web browser from Haskell
+description:    Open a web browser from Haskell. Windows, macOS, Linux and BSD are supported.
+category:       Web
+homepage:       https://github.com/mpilgrem/open-browser
+bug-reports:    https://github.com/mpilgrem/open-browser/issues
+author:         rightfold
+maintainer:     public@pilgrem.com
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+tested-with:
+    GHC >= 8.4
+extra-source-files:
+    CHANGELOG.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/mpilgrem/open-browser
+
+flag example
+  description: Build the example application
+  manual: True
+  default: False
+
+library
+  hs-source-dirs:
+      lib
+  exposed-modules:
+      Web.Browser
+  build-depends:
+      base ==4.*
+  default-language: Haskell2010
+  if os(windows)
+    other-modules:
+        Web.Browser.OS
+    hs-source-dirs:
+        lib/windows
+    build-depends:
+        Win32 <3
+  else
+    if os(darwin)
+      other-modules:
+          Web.Browser.OS
+      hs-source-dirs:
+          lib/unix-like/open
+      build-depends:
+          process >=1.2.0.0 && <2
+    else
+      if os(linux) || os(freebsd) || os(openbsd) || os(netbsd)
+        other-modules:
+            Web.Browser.OS
+        hs-source-dirs:
+            lib/unix-like/xdg-open
+        build-depends:
+            process >=1.2.0.0 && <2
+      else
+        other-modules:
+            Web.Browser.OS
+        hs-source-dirs:
+            lib/unsupported-os
+
+executable open-browser-example
+  main-is: Main.hs
+  hs-source-dirs:
+      example
+  build-depends:
+      base ==4.*
+    , open-browser
+  default-language: Haskell2010
+  if !flag(example)
+    buildable: False
diff --git a/stack.yaml b/stack.yaml
deleted file mode 100644
--- a/stack.yaml
+++ /dev/null
@@ -1,1 +0,0 @@
-snapshot: lts-23.14 # GHC 9.8.4
diff --git a/stack.yaml.lock b/stack.yaml.lock
deleted file mode 100644
--- a/stack.yaml.lock
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file was autogenerated by Stack.
-# You should not edit this file by hand.
-# For more information, please see the documentation at:
-#   https://docs.haskellstack.org/en/stable/topics/lock_files
-
-packages: []
-snapshots:
-- completed:
-    sha256: 1964d439d2a152be4238053f3f997a09fb348391984daab86d724975ef9a423f
-    size: 683814
-    url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/14.yaml
-  original: lts-23.14
