Why pattern-matching failure is not catching by my exception handler excToStr
in this case?
I have a handler of an incoming POST request as under the control of the Scotty Web framework:
...
import qualified Web.Scotty as W
...
W.post "/some/endpoint" $ excToStr "Cannot handle it!" $ do
b <- W.body
-- throwString "aaa" <--- THIS IS HANDLED FINE!
Just x::Maybe SomeMyType <- pure (decode b) -- BUT NOT THIS PATTERN-MATCHING FAILURE!
liftIO $ print $ show x
W.text "OK"
where excToStr
is mine and it looks like:
...
import qualified Data.Text.Lazy as LT
...
excH :: (String -> String) -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excH mkErr m = catchAnyDeep m (W.text . cs . mkErr . show)
excToStr :: String -> ActionT LT.Text IO () -> ActionT LT.Text IO ()
excToStr errMsg = excH (\details -> errMsg <> " (" <> details <> ")")
catchAnyDeep
is from safe-exceptions library. I tried another functions as well (catchAny
, handle
, catch
, etc) - without success. The crux of the problem is that when incoming body cannot be decoded successfully (and decode
returns Nothing
instead of Just x
), then pattern-match fails, so I expect that my extToStr
(ie. excH
) will handle it because catchAnyDeep
(and catchAny
) handles ANY exception (including pattern-match failures, right?):
catchAny :: MonadCatch m => m a -> (SomeException -> m a) -> m a
and
catchAnyDeep :: (MonadCatch m, MonadIO m, NFData a) => m a -> (SomeException -> m a) -> m a
.
If I throw just an exception with throwString
then it works as expected (the exception gets caught). But the pattern matching failure leads to an HTTP internal error 500 with a message "Pattern match failure in do expression at....". How to handle pattern-matching exceptions as well?