Dependencies between components should ideally be as explicit and as few as possible. Dependency injection is one good way of achieving this, but even global variables or singletons are more clearly self-documenting than exceptions. A piece of code that returns a value or makes a call to some functionality in another piece of code is easy to understand. If instead, that code throws an exception, then it sends the reader on a voyage of discovery throughout the codebase to investigate all the places that catch this type of exception, and which of those pieces of code can ever potentially be higher in the call stack than the piece that throws it.
The only reason we even put up with such complexity in the case of handling errors is that it is the one problem that is ubiquitous to every piece of software ever written and therefore merits its own first-class language support.