Discussion: "Notes on structured concurrency, or: Go statement considered harmful"

Right… every system has a way to handle errors explicitly – in regular Python or Trio you use try/except/finally; in asyncio or gevent you use try/except/finally+some custom method to explicitly check exceptions in background tasks. But the key word in the text you quoted is unhandled – sometimes people don’t write explicit error handling code like this, so as framework authors we have to decide what should happen. We have to pick some default behavior.

The Zen of Python suggests: Errors should never pass silently, unless explicitly silenced. That’s what Python and Trio do: exceptions keep going until you catch them or until the program exits. Of course this may not always be what you want (like in your application server), but the solution is easy enough: just catch the exception and do something else with it :slight_smile: It’s the safest default, but you can always override it.

In other frameworks like asyncio or gevent, if an error occurs in a background task, and you don’t remember to explicitly check for it, then they just print a message on the console and then discard the error. Sometimes, if you’re lucky, this might be what you want. But the framework really has no way to know which unhandled errors you intended to discard, and which ones are actually some serious bug that needs to be handled. So it’s a pretty dangerous thing to do by default.