nico.fyi
    Published on

    What is "async" must be await-ed

    Subtle bug that could cause you headache

    Authors

    Several months back, I experienced a sudden crash in my pull request on the Monika project, which caught my team off guard during the PR review, as noted in this issue comment.

    I was surprised because I expected any errors to be intercepted by the try-catch blocks already in place, which should have prevented the crash. However, the error slipped through and crashed the app!

    After extensive debugging, I realized the root cause: the error was originating from an async function that wasn't invoked with await. Here's an illustration:

    const main = async () => {
      try {
        doSomething() // the bug
      } catch (error) {
        console.log('here?')
      }
    }
    
    const doSomething = async () => {
      throw new Error(`Error from doSomething`)
    }
    
    main()
    

    The issue arose because the doSomething function, even though it throws an error, was mistakenly not called with await. This oversight caused the try-catch block not to catch the error.

    To ensure errors in async functions are captured by try-catch blocks, these functions must be invoked with an await, even when they don't perform any asynchronous operations.

    Alternatively, I could also remove the async from the doSomething function since it doesn't perform any asynchronous operations. This way, I don't need to use await when calling the function.

    You might think it's silly to make this mistake. But mind you, the code in the repository had more lines and was more complex.


    As I pointed out at the beginning, the crash was identified during PR Review. This highlights the advantage of crafting an effective pull request that aids reviewers in both comprehending and testing the PR. For more insights on how to create and review pull requests, take a look at my book!