{
  "$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"
}