I'm afraid I do not agree with you. This is a radically different subject and perhaps we may debate it elsewhere but for now I will simply posit that data that was not expected and does not fit the original return space are certainly "errors" that we can safeguard against. Exceptions are used to circumvent things that are beyond our control (i.e. lost socket connections, no more disc space...)
It's not an error because it does not lead to misbehavior. For example, if you have a socket and make it non blocking. If you read and there is no data, it will be an exception, in the sense that in the classical Berkley Sockets C API it returns -1 and sets errno, and a more high level Pascal API may use exceptions for it. But you made that socket explicetly non blocking, with the knowledge that reading when no data available is an option and will occur. If you made the socket non blocking this behavior is actually the behavior you want to have, and therefore it can't be an error, in the same way if I go to McDonalds and buy a cheeseburger, not getting a healthy meal is not an error but what I wanted.
Exceptions are just a way to extend the output space through additional control paths that carry information outside the normal return type. It's not that often used in Pascal, I think because Exceptions in Lazarus are anyoing, while in other languages exceptions that will be cought are usually not thrown in the debugger, but for example in Java it's very common, if you want to check if a file has a certain encoding, trying to decode it and if there was an exception you know that the file has not the desired encoding.
One example where I have used Exceptions quite a lot was in my STAX library. Basically the current design of Threads has the problem that you need to regularly check if you are terminated. Long lasting blocking functions (such as a read on a socket) basically mean your thread cannot be terminated until that function returned. So when I created STAX, I thought on how I can turn this polling mechanism into a notification mechanism, and what I did is when you are blocking you call the scheduler to be re scheduled. When you terminate that task, the scheduler will wake up the Task and raise an exception. This will prematurely interrupt the blocking operation, and because it was interrupted, it does not have an result, so instead the exception must be handled.
This allows any task to be stopped at any time, it gives the Task the oportunity to die handle the termination and do some additional stuff before stopping by handling the exception, but even if the exception is not handled, it will execute all the finally blocks before it will forcefully stop the task, making even the "non graceful" termination still completely safe.
And before anyone is inclined to call premature stopping of a thread an error, for example this termination mechanism is what I have used for a socket receive with a timeout, simply do a blocking call, and if the call has not returned after the timeout, the terminate exception stops the blocking call, and gracefully shuts down the task. So it's not an error, it is just a feature I use, as intendet to accomplish a certain thing
I've actually built something similar prototypically for Linux pthreads using pthread signals, which allow to seize the execution context of a thread and then can raise an exception in that context, it's really hacky and defenetly not in any way production ready, but this addresses a clear need that anyone who has ever worked with threads has probably encountered at one point.