open62541pp 0.16.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
Error handling

In OPC UA, status codes are used to indicate the result of an operation or request. They are returned as part of service responses and node values to describe the outcome, including success, failure, or error conditions. The underlying open62541 C-library adopts this model, returning a status code (UA_StatusCode) from any function that may encounter an error. In open62541pp, the UA_StatusCode is wrapped as opcua::StatusCode and enhanced with utility functions for easier use.

The following two error handling methods are used, which are described below:

  1. Exceptions in the high-level classes (opcua namespace)
  2. Result return types for low-level functions (opcua::services namespace)

Exceptions

Exceptions are the main used mechanism to report bad status codes in function calls.

The bases exception type opcua::BadStatus wraps a bad status code. The underlying status code can be accessed with opcua::BadStatus::code(). opcua::BadStatus::what() provides a human-readable name for the status code.

Example:

opcua::Node node(client, id);
try {
const auto var = node.readValue(); // may throw opcua::BadStatus
} catch (const opcua::BadStatus& e) {
std::cerr << "Bad status: " << e.code() << ": " << e.what() << std::endl;
}
Exception for bad status codes from open62541 UA_STATUSCODE_*.
Definition exception.hpp:15
UA_StatusCode code() const noexcept
Definition exception.hpp:20
const char * what() const noexcept override
Definition exception.hpp:24
UA_NodeId wrapper class.
Definition types.hpp:590
High-level node class to access node attribute, browse and populate address space.
Definition server.hpp:30

Result type

The opcua::Result<T> type wraps both the result of a function and the corresponding status code. Its design is similar to std::optional or std::expected, making it suitable for scenarios that involve error handling without exceptions. The key difference from std::expected is that the status code is always present, while the result is only available if the status code indicates success. This approach avoids the performance overhead of exceptions and enhances clarity in function signatures. It also supports finer control over error management, especially in asynchronous contexts.

Key functions:

Example:

if (result.code().isBad()) {
std::cerr << "Bad status: " << result.code().get() << ": " << result.code().name() << std::endl;
} else {
const opcua::Variant value = result.value();
}
The template class Result encapsulates a StatusCode and optionally a value.
Definition result.hpp:53
constexpr T & value() &
Get the value of the Result.
Definition result.hpp:162
constexpr StatusCode code() const noexcept
Get the StatusCode of the Result.
Definition result.hpp:140
constexpr bool isBad() const noexcept
Check if the status code is bad.
Definition types.hpp:76
std::string_view name() const noexcept
Get human-readable name of the StatusCode.
Definition types.hpp:61
constexpr UA_StatusCode get() const noexcept
Explicitly get underlying UA_StatusCode.
Definition types.hpp:53
UA_Variant wrapper class.
Definition types.hpp:887
Result< Variant > readValue(T &connection, const NodeId &id) noexcept
Read the AttributeId::Value attribute of a node.

Error propagation is user callbacks

Since callbacks are executed within the open62541 C event loop, which does not support exceptions, any exceptions thrown inside user-defined callbacks are automatically caught and stored by opcua::detail::ExceptionCatcher. These exceptions are then propagated to the opcua::Client::run() and opcua::Server::run() functions, ensuring they can be handled properly.

Example:

// define callback that throws an exception
client.onSessionActivated([] { throw std::runtime_error("User exception!"); });
client.connect("opc.tcp://localhost:4840");
try {
client.run(); // exceptions in callbacks are propagated to the run call
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
High-level client class.
Definition client.hpp:121
void connect(std::string_view endpointUrl)
Connect to the selected server.
void onSessionActivated(StateCallback callback)
Set a state callback that will be called after the session is activated.
void run()
Run the client's main loop by. This method will block until Client::stop is called.