It's valid to try to launch on a cancelled parent job, because it means that your code can just call launch without worrying about race conditions that could occur between that call and something cancelling the parent. Launching a coroutine is a complicated process, the parent job could be cancelled at any point in that process. If it threw instead, there would have to be a mechanism to atomically check if the job was still active, and only launch if it was, and I think that would be very complicated from both implementation and api perspectives - eg probably force every single launch call to be inside a try/catch.