Let’s say in your pirate game you need to transfer loot from one player (A) to another (B), over the network.
Let’s say you use HTTP.
Let’s say that you call your server to start the transfer.
The HTTP request library returns back a response object, with a status code, and a response body.
However, maybe player A’s network connection fails before the request completes. The library can do a few things. It can return a response object indicating what happened, or it can throw an exception.
In this case the library just returns a status code and response body, and since an invalid network connection does not fit within the bounds of that interface, all it can do is either silently fail or throw an exception since this is an exceptional condition. You don’t normally expect this to happen, it’s an exception.
Exceptions are used whenever you want to handle control flow that is out of bounds of the consumed interface. For example we get by without exceptions in C, because everything has to return an error code (or maybe a pointer to where one gets populated). But then you have to check “if this didn’t fail” everywhere. But then we’re just getting into personal preferences.