Nim
Nim copied to clipboard
`try-except` with `await` doesn't work in `defer` block
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.
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()
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()
Fixed in #25030