I’d like to raise a practical issue with the current direction of error-handling support. In my experience, existing models still leave too much uncertainty for both human and programmatic consumers of error information. I’m interested in whether a more general boost::exception-style mechanism could preserve richer diagnostic context without forcing users into narrow error codes or lossy secondary return values. A general-purpose error-handling facility should preserve as much diagnostic information as possible, keep that information available for both human and programmatic consumers, and remain highly reliable itself. An error message must enable the user of the program to identify the cause and investigate or fix it without further assistance, without experiments, without guesswork, and without help from third parties. It must also be usable programmatically. To do that, it must identify four points: * The action triggered by the user or by an automated process in whose context the error occurred, including the consequences of incomplete execution, for example: “Not all mails could be retrieved; the missing ones are still on the server.” This is not the task of error handling itself, but of the top level, the user of the error-handling facility. * The cause, that is, the detected state, for example a full disk. * The object, such as a file path, device name, or similar, on which * the named operation failed: reading, writing, opening a window. Unless there are compelling reasons to the contrary, these points must have top priority; neglecting them is inexcusable. It is not enough to simply produce text at the end; rather, the text must be part of the diagnosis that begins with the message. Ideally, it implicitly suggests a necessary or at least obvious course of action. For logging purposes, it must also allow later diagnosis. That is the task of the caller or an external instance, but the error must include the point of state recognition and the triggering operation. Taken together, these requirements mean that many participating levels and instances must collect information, and each must also have the opportunity to make use of it and act accordingly. At the same time, no error-handling mechanism itself may become a source of errors; it must handle any runtime errors occurring within itself definitively. Errors that occur during error handling do not only lead to technical difficulties, but “errors during errors” can also conceal or distort the original error, or lead to unmanageable or otherwise unrecoverable follow-up errors. In my view, there is no alternative to making error handling itself free of errors. Existing solutions often do not take this requirement into account. The widely unsatisfactory state of error messages shows that more is needed than yet another proposal. A good solution in boost could show what error messages should look like in the first place. Udo -- Mit Radwegen lernte ich den Menschen kennen. http://radwege.udoline.de/ GPG: A245 F153 0636 6E34 E2F3 E1EB 817A B14D 3E7E 482E
śr., 24 cze 2026 o 19:16 Udo Steinbach via Boost <boost@lists.boost.org> napisał(a):
I’d like to raise a practical issue with the current direction of error-handling support. In my experience, existing models still leave too much uncertainty for both human and programmatic consumers of error information. I’m interested in whether a more general boost::exception-style mechanism could preserve richer diagnostic context without forcing users into narrow error codes or lossy secondary return values.
A general-purpose error-handling facility should preserve as much diagnostic information as possible, keep that information available for both human and programmatic consumers, and remain highly reliable itself.
An error message must enable the user of the program to identify the cause and investigate or fix it without further assistance, without experiments, without guesswork, and without help from third parties. It must also be usable programmatically.
To do that, it must identify four points: * The action triggered by the user or by an automated process in whose context the error occurred, including the consequences of incomplete execution, for example: “Not all mails could be retrieved; the missing ones are still on the server.” This is not the task of error handling itself, but of the top level, the user of the error-handling facility. * The cause, that is, the detected state, for example a full disk. * The object, such as a file path, device name, or similar, on which * the named operation failed: reading, writing, opening a window. Unless there are compelling reasons to the contrary, these points must have top priority; neglecting them is inexcusable.
It is not enough to simply produce text at the end; rather, the text must be part of the diagnosis that begins with the message. Ideally, it implicitly suggests a necessary or at least obvious course of action. For logging purposes, it must also allow later diagnosis. That is the task of the caller or an external instance, but the error must include the point of state recognition and the triggering operation. Taken together, these requirements mean that many participating levels and instances must collect information, and each must also have the opportunity to make use of it and act accordingly.
At the same time, no error-handling mechanism itself may become a source of errors; it must handle any runtime errors occurring within itself definitively. Errors that occur during error handling do not only lead to technical difficulties, but “errors during errors” can also conceal or distort the original error, or lead to unmanageable or otherwise unrecoverable follow-up errors. In my view, there is no alternative to making error handling itself free of errors. Existing solutions often do not take this requirement into account.
The widely unsatisfactory state of error messages shows that more is needed than yet another proposal. A good solution in boost could show what error messages should look like in the first place.
Hi Udo, What you describe sounds like an expectation of well designed programs and servers. Decent error reporting would be included in the program's architecture design and API design. It would require a shift from "this API is for returning best offers" to "this API is for returning offers or communicating why it was not possible to return best offers". You need to design how/if you will be translating error messages. Different error messages are reported to different users. For security or business-safety reasons you do not explain in detail what went wrong in the server to users. But you do communicate details to system maintenance teams via logs. But logging a lot of information is extremely costly, so you will end up balancing between the amount of log details and the storage consumption. This process of communicating errors becomes part of the business logic. I do not think a single library or a single "mechanism" for reporting errors would be enough to accomplish this. You have in Boost libraries that offer error types capable of setting and getting arbitrary pieces of information of arbitrary types (Boost.Exception), that allow integrating with other mechanisms of error handling from other libraries (Boost.Outcome), libraries that offer easy logging of different pieces of error-related data at different levels (Boost.LEAF) but all of them, and I think any other, are enough, and will not substitute for a server/program design that considers error reporting at every level. Regards, &rzej;
It would require a shift from "this API is for returning best offers"
It requires both. As long as you have options for action, you need primitive numbers, sure. Done. But as soon as there's a possibility that text needs to appear somewhere at the top, you also need a transport mechanism for that number and any other information collected along the way.
I do not think a single library or a single "mechanism" for reporting errors
All conceivable error-handling mechanisms have two things in common. They all have to convert infos to text. And they need safe collect and transport. Since the collected information is of unknown—and in any case, varying—types, the transport mechanism must be a heterogeneous container.
For security or business-safety reasons you do not explain in detail
That can be done at the handler, the info-to-text-converter, because it can ask the infos themself or look for its types. As far as I can tell, all the processing mechanisms I know of that go beyond primitive types suffer from one flaw: they are not error-free themselves. However, this is a prerequisite for ensuring that I don't have to deal with other errors during error handling. If a piece of information cannot be added, then `push_back()` must not throw under any circumstances. There must be no further errors between the detection of the error condition and the processing of the error object. Any error that occurs must be catched. The transport has to be error-neutral. -- Mit Radwegen lernte ich den Menschen kennen. http://radwege.udoline.de/ GPG: A245 F153 0636 6E34 E2F3 E1EB 817A B14D 3E7E 482E
On Wed, Jun 24, 2026 at 1:16 PM Udo Steinbach via Boost < boost@lists.boost.org> wrote:
I’d like to raise a practical issue with the current direction of error-handling support. In my experience, existing models still leave too much uncertainty for both human and programmatic consumers of error information. I’m interested in whether a more general boost::exception-style mechanism could preserve richer diagnostic context without forcing users into narrow error codes or lossy secondary return values.
A general-purpose error-handling facility should preserve as much diagnostic information as possible, keep that information available for both human and programmatic consumers, and remain highly reliable itself.
An error message must enable the user of the program to identify the cause and investigate or fix it without further assistance, without experiments, without guesswork, and without help from third parties. It must also be usable programmatically.
Look at Boost LEAF, it lets you communicate arbitrary context with any error, with or without exceptions. You can associate arbitrary context with any failure, the error objects are communicated with type safety. At an error handling scope you have the option to format a user-friendly message based on the available data, or an automatic developer-friendly message, or to serialize everything into a machine-readable format (nlohmann and Boost.JSON are directly supported, but the serialization API is extensible.) Emil
On 6/25/26 23:16, Emil Dotchevski via Boost wrote:
Look at Boost LEAF, it lets you communicate arbitrary context with any error, with or without exceptions.
You can associate arbitrary context with any failure, the error objects are communicated with type safety. At an error handling scope you have the option to format a user-friendly message based on the available data, or an automatic developer-friendly message, or to serialize everything into a machine-readable format (nlohmann and Boost.JSON are directly supported, but the serialization API is extensible.)
A word of warning about LEAF: it uses thread-local storage in a way that is incompatible with thread-jumping code, including but not limited to Boost.Fiber and the proposed Boost.Capy, and possibly C++ coroutines in general. This problem was noted when LEAF was first reviewed, but it has gotten much worse with the introduction of C++ coroutines. This limitation is mentioned in the LEAF documentation, but you have to look a bit to find it and read between the lines to understand its full implications. (The relevant documentation section is https://www.boost.org/doc/libs/latest/libs/leaf/doc/html/index.html#tutorial...). -- Rainer Deyke - rainerd@eldwood.com
On Fri, Jun 26, 2026 at 3:11 AM Rainer Deyke via Boost < boost@lists.boost.org> wrote:
On 6/25/26 23:16, Emil Dotchevski via Boost wrote:
Look at Boost LEAF, it lets you communicate arbitrary context with any error, with or without exceptions.
You can associate arbitrary context with any failure, the error objects are communicated with type safety. At an error handling scope you have the option to format a user-friendly message based on the available data, or an automatic developer-friendly message, or to serialize everything into a machine-readable format (nlohmann and Boost.JSON are directly supported, but the serialization API is extensible.)
A word of warning about LEAF: it uses thread-local storage in a way that is incompatible with thread-jumping code
Yes, when using LEAF, jumping between threads requires that the error objects are collected and later released in the error handling thread. Just like std::exception_ptr can capture an exception object, leaf::result can capture any number of error objects (plus a C++ exception, if present).
OK, I will take a deeper look at leaf and test it. -- Nur wer resigniert hat, benutzt noch Radwege. http://radwege.udoline.de/ GPG: A245 F153 0636 6E34 E2F3 E1EB 817A B14D 3E7E 482E
participants (4)
-
Andrzej Krzemienski -
Emil Dotchevski -
Rainer Deyke -
Udo Steinbach