{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreifsg4obzurcq5qf6du7ckxqpkxcmejh4koypirs52fao3g4jvhs4q",
"uri": "at://did:plc:pi6woz4d47bkuws673w2il2r/app.bsky.feed.post/3mmkgyij63qg2"
},
"path": "/t/exception-annotations-lay-of-the-land/14056#post_8",
"publishedAt": "2026-05-23T21:12:15.000Z",
"site": "https://discourse.haskell.org",
"tags": [
"this repo",
"@SomeException"
],
"textContent": "Embarrassingly, I hadn’t considered `WhileHandling` then thinking about the rethrow behaviours. I was thinking about the possibility of ending up with duplicate `Backtraces` annotations in the same annotation list.\n\nI’ve created the this repo to experiment (using GHC 9.14.1)\n\nIt has three cases:\n\n\n catchAndThrow :: IO a -> IO a\n catchAndThrow action = catch @SomeException action throwIO\n\n -- like 'catchAndThrow', but with a type of exception for which 'toException'\n -- preserves context, here we used 'ExceptionWithContext'\n catchAndThrow' :: IO a -> IO a\n catchAndThrow' action = catch @(ExceptionWithContext SomeException) action throwIO\n\n\n -- after migrating to 'catchNoPropagate' + 'rethrowIO'\n catchAndRethrow :: IO a -> IO a\n catchAndRethrow action = catchNoPropagate @(ExceptionWithContext SomeException) action rethrowIO\n\n\nIn the first case, the exception structure looks like\n\n\n IOException\n |\n +- WhileHandling\n | |\n | `- IOException\n | |\n | `- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:30:7 ...\n |\n `- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:15:62 ...\n\n\nThe original exception is inside the `WhileHandling` annotation, with the original backtrace. The rethrown exception has the backtrace of the rethrow.\n\nFor the second case (the exception whose `toException` doesn’t clean the context) we have\n\n\n IOException\n |\n +- WhileHandling\n | |\n | `- IOException\n | |\n | `- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:30:7 ...\n |\n +- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:20:84 ...\n |\n `- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:30:7 ...\n\n\nThe `WhileHandling` is still there, but the rethrown exception (confusingly?) has two `Backtraces` annotations.\n\nIn the third case, the rethrow is not visible in the exception, we only have the original `Backtraces`:\n\n\n IOException\n |\n `- Backtrace: HasCallStack backtrace:/ throwIO, called at app/Main.hs:30:7 ...\n",
"title": "Exception Annotations: Lay of the Land"
}