Not "threads are more ergonomic than async/await", but "threads and channels can be ergonomic".
I've been a big fan and user of async/await in various languages for over a decade now, and it can absolutely improve reading sequential asynchronous logic flow, but lets not pretend it isn't without tradeoffs. Compared to wrangling synchronization contexts and function colors, channels can be rather straightforward.
Errors as return value are a “function color” too (in practice, you need to propagate it upwards the stack and it “contaminates” your code the same way as async/await). And in fact it interacts better with async/await (like in Rust) than with channels…
I've been a big fan and user of async/await in various languages for over a decade now, and it can absolutely improve reading sequential asynchronous logic flow, but lets not pretend it isn't without tradeoffs. Compared to wrangling synchronization contexts and function colors, channels can be rather straightforward.