That's only a problem when you decide that the way to do error handling is exceptions. When you go with a strongly typed functional programming language, you throw exceptions away, and the fact that something can error, and what kinds of errors it can produce, are encoded into the type system.
So yes, generating errors at a deep level and catching them at a higher one is a normal pard of the system design, it's purely functional, ando nothing strange happens, in very large systems. You ADT the errors, pipe up entire families of them, and select what you manage. It's significantly easier than exceptions, in the sense that I can be sure when I've validated the error.
It's practical, and typically one dedicates less code to the error handling than, say, yor typical enterprise Java program that is terrified of runtime exceptions and null checks every step of the way. In fact, I'd argue this is the main selling point of strongly typed FP.
> When you go with a strongly typed functional programming language, you throw exceptions away, and the fact that something can error, and what kinds of errors it can produce, are encoded into the type system.
You’ve just reinvented checked exceptions, good job.