Really, error handling has been my big beef with CS education for like 40 years. There is none.
Error handling has been left to engineers, and when left to they own devices engineers will almost always make the wrong choice from a user point of view.
Engineering need to think of error messages this way: the error message is there to help people (which might be fellow engineers, support, and/or and your consultants) identify the error quickly so that they can manage the user's expectations, fix the error, and/or both.
Unfortunately, many engineering paradigms make this an impossible task.
Layering and encapsulation means that you have little idea what's happening downstream or how the downstream stuff actually works, but the lower-level you are the less likely the error will mean anything to the end-user.
Then, it's a question of who's responsible for handling the error? If you're on the backend, where does it go? Does the user care that the backend microservice can't connect to the database? Heck, the UI probably has no idea what's happening back there.
However, for accurate troubleshooting detail is needed.
For many orgs, leaving transaction IDs in your log files is the primary way that you figure out errors, especially in big distributed systems. That doesn't really help end-users, and requires developer discipline, something many engineering teams find challenging.
Ideally error objects would aggregate error codes up the stack, so that if an error occurs you can at least present technical people with the errors that were thrown..and they can search through the source code trying to find that unique error code. But designing that is difficult; conceptually you don't want a list of 500 error codes being thrown upwards, one from each function in the call chain. But sometimes you do.
Anyway, error handling design really should be part of the initial architecture, but it usually isn't because architecture guys don't really understand support.
Error handling has been left to engineers, and when left to they own devices engineers will almost always make the wrong choice from a user point of view.
Engineering need to think of error messages this way: the error message is there to help people (which might be fellow engineers, support, and/or and your consultants) identify the error quickly so that they can manage the user's expectations, fix the error, and/or both.
Unfortunately, many engineering paradigms make this an impossible task.
Layering and encapsulation means that you have little idea what's happening downstream or how the downstream stuff actually works, but the lower-level you are the less likely the error will mean anything to the end-user.
Then, it's a question of who's responsible for handling the error? If you're on the backend, where does it go? Does the user care that the backend microservice can't connect to the database? Heck, the UI probably has no idea what's happening back there.
However, for accurate troubleshooting detail is needed.
For many orgs, leaving transaction IDs in your log files is the primary way that you figure out errors, especially in big distributed systems. That doesn't really help end-users, and requires developer discipline, something many engineering teams find challenging.
Ideally error objects would aggregate error codes up the stack, so that if an error occurs you can at least present technical people with the errors that were thrown..and they can search through the source code trying to find that unique error code. But designing that is difficult; conceptually you don't want a list of 500 error codes being thrown upwards, one from each function in the call chain. But sometimes you do.
Anyway, error handling design really should be part of the initial architecture, but it usually isn't because architecture guys don't really understand support.