No value judgement here, I don't think, at least not from me (though of course my values inform every opinion I have, including this one). I simply claim that every path is equivalent, and all must be considered. I claim there is no so-called "happy path" - a term I reject - nor do "errors" really exist.
There is one case where the socket send succeeded, and another where it failed. There is one case where the file name encoding is valid, and another where it is not. And so on. It makes no sense, in my view, for one case to be handled with one language mechanism and the other case to be handled with another.
By comparison, there is (or so I claim!) no valid path where a null pointer is dereferenced, or where a value is divided by zero. So I will accept the requirement for some other mechanism for dealing with these - though by the time the code is released to the wild, I would hope that all such occurrences would have been eliminated.
The correct behavior for not just the vast majority of these conditions but virtually all of them is the same: propagate the error. You aren't going to sit around and try to "recover" from failing to send a packet or encode a filename: you just report it to higher level code. There might be something you can do at a higher level--such as reconnecting or using a different server from a load balancing list--but at that point the exact reason is irrelevant (and yet should be maintained in case the higher level code needs to inform the user in either a dialog or a log file): failure is, virtually all of the time, boolean in nature and a non-local phenomenon.
My opinion was informed by writing the higher levels rather than the lower ones! Yes, the code absolutely is going to try to recover from sending a packet, because it was sending that in service of some larger goal that now needs unwinding partway through. And, yes, it is going to try to reconnect, or use a different server - or whatever.
The thing it really doesn't want to do is punt the issue on to some higher level. Because there isn't one.
But, equally, you don't want to be swallowing interesting problems that genuinely indicate actual bugs. Those, you do want to pass on (and due to the lack of any higher level, your process will be killed, and some mechanism will spring into action to produce a report).
There is one case where the socket send succeeded, and another where it failed. There is one case where the file name encoding is valid, and another where it is not. And so on. It makes no sense, in my view, for one case to be handled with one language mechanism and the other case to be handled with another.
By comparison, there is (or so I claim!) no valid path where a null pointer is dereferenced, or where a value is divided by zero. So I will accept the requirement for some other mechanism for dealing with these - though by the time the code is released to the wild, I would hope that all such occurrences would have been eliminated.