Your scenario is perfectly valid IMHO
You wait until you need to create the exception and then , you create it
Regarding this
* How is it easier to forget to compare against an exception code instead of comparing against a message?
You add an explicit comparison and then you couple the caller to method.
IF you forget to check return types your code fails.
Expections are more gentle. You only write happy paths. Unless you decide to handle bad paths.
But you can skip a lot of stack frames until you decide what to do.
You can remove all those ifs and just bubble the problem until someone catches it.
cleaner and more robust code !