And you're right, this is a good compromise.
When it comes to exceptions (and many other things) you realize some boundaries are more important than others. If you're building, say, a database access library that has a well-defined API, you are better off defining a good set of meaningful exceptions.
Inside a particular module, however, creating new exception classes tends to create more problems than it is worth. I can't tell you how many times I've seen basically the same exception defined three or four times by different programmers in different parts of the same system.
Even when you look at the "better" examples of exception hierarchies the results are frequently depressingly bad. For instance, many database access APIs just give a SQLException or the equivalent thereof. Some of them will add a huge range of Exceptions that are pretty superfluous such as InvalidTableNameException, InvalidColumnNameException, YouViolatedTheTypingRulesOfDatabaseXException (all of which should be DontProgramaticallyGenerateSQLException) but they never seem to have a DuplicateKeyException which is the one case where you actually might want to do something different from all of the others.