Nim icon indicating copy to clipboard operation
Nim copied to clipboard

`try-except` with `await` doesn't work in `defer` block

Open darkestpigeon opened this issue 5 months ago • 2 comments

Nim Version

Both

Nim Compiler Version 2.2.4 [Linux: amd64]
Compiled at 2025-04-22
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: f7145dd26efeeeb6eeae6fff64

and

Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2025-06-01
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: 807840dc5bda1e6e218be24d704efb77421e0ccb
active boot switches: -d:release

Description

Here is an example

import std/asyncdispatch


proc doStuff {.async.} =
  defer:
    for i in 0..<3:
      # doesnt work
      try:
        await sleepAsync(10)
      except:
        discard

      # works as intended
      # await sleepAsync(10)

      echo "bbb", i

  for i in 0..<3:
    try:
      await sleepAsync(10)
    except:
      discard
    echo "aaa", i

  raise newException(CatchableError, "")

proc main() {.async.} =
  try:
    await doStuff()
  except:
    echo "err"

waitFor main()

Current Output

aaa0
aaa1
aaa2
err

Expected Output

aaa0
aaa1
aaa2
bbb0
bbb1
bbb2
err

Known Workarounds

In the code above, removing the try-except and leaving just await gives expected behavior.

Additional Information

If the defer block is not triggered by an exception, the program also works as intended.

darkestpigeon avatar Jun 05 '25 12:06 darkestpigeon

This has nothing to do with defer as the following program shows the same wrong behavior:


import std/asyncdispatch

proc doStuff {.async.} =
  try:
    for i in 0..<3:
      try:
        await sleepAsync(10)
      except:
        discard
      echo "aaa", i

    raise newException(CatchableError, "")
  finally:
    for i in 0..<3:
      # doesnt work
      try:
        await sleepAsync(10)
      except:
        discard

      # works as intended
      # await sleepAsync(10)

      echo "bbb", i

proc main() {.async.} =
  try:
    await doStuff()
  except:
    echo "err"

waitFor main()

Araq avatar Jun 11 '25 09:06 Araq

Workaround: Avoid complex finally sections, move logic to an async helper proc:


import std/asyncdispatch

proc action() {.async.} =
  for i in 0..<3:
    # doesnt work
    try:
      await sleepAsync(10)
    except:
      discard

    # works as intended
    # await sleepAsync(10)

    echo "bbb", i

proc doStuff {.async.} =
  try:
    for i in 0..<3:
      try:
        await sleepAsync(10)
      except:
        discard
      echo "aaa", i

    raise newException(CatchableError, "")
  finally:
    await action()

proc main() {.async.} =
  try:
    await doStuff()
  except:
    echo "err"

waitFor main()

Araq avatar Jun 11 '25 09:06 Araq

Fixed in #25030

yglukhov avatar Jul 09 '25 08:07 yglukhov