C · recipe
Handle errors and reconnect in C
open62541's client keeps its own state machine. Call UA_Client_run_iterate in a loop, watch the channel and session state, and let the client re-establish rather than tearing down and rebuilding. Classify the status code before retrying.
| Stack | open62541 |
|---|---|
| Version | 1.5.8 |
The code
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/client_subscriptions.h>
#include <stdio.h>
#include <unistd.h>
static UA_Boolean isWorthRetrying(UA_StatusCode c) {
switch (c) {
case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED:
case UA_STATUSCODE_BADUSERACCESSDENIED:
case UA_STATUSCODE_BADSERVICEUNSUPPORTED:
return false; /* needs a human; retrying just floods the log */
default:
return true;
}
}
int main(void) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(cc);
cc->timeout = 5000;
cc->requestedSessionTimeout = 60000;
unsigned backoff = 1;
while (1) {
UA_SecureChannelState ch;
UA_SessionState se;
UA_StatusCode connectStatus;
UA_Client_getState(client, &ch, &se, &connectStatus);
if (se != UA_SESSIONSTATE_ACTIVATED) {
UA_StatusCode rc = UA_Client_connect(client, "opc.tcp://opcua.umati.app:4840");
if (rc != UA_STATUSCODE_GOOD) {
printf("connect failed: %s\n", UA_StatusCode_name(rc));
if (!isWorthRetrying(rc)) {
printf("permanent - needs configuration, giving up\n");
break;
}
sleep(backoff);
backoff = backoff < 60 ? backoff * 2 : 60; /* cap the backoff */
continue;
}
printf("connected\n");
backoff = 1;
}
/* drives reconnection, keep-alive and publish processing */
UA_Client_run_iterate(client, 1000);
}
UA_Client_delete(client);
return 0;
}
What it prints
connected
connect failed: BadConnectionClosed
connected
# with a bad certificate instead:
# connect failed: BadCertificateUntrusted
# permanent - needs configuration, giving up
Notes
- UA_Client_getState gives you the channel state, session state and last connect status separately. All three matter when diagnosing a flapping connection.
- UA_Client_run_iterate does the work: keep-alive, reconnection and publish processing. It is not optional.
- Do not retry certificate or permission errors. They fail identically forever, and the retry loop buries the one log line that would have told you why.
- Cap the backoff and add jitter across a fleet. Synchronised reconnects turn a network blip into an outage.
- After reconnecting, confirm monitored items are still reporting. The client may have transferred the subscription, or it may have silently lost it.
What breaks first
An embedded client retries a permanent error forever and fills its flash with logs
Classify status codes before retrying, as above. Configuration errors need an operator, not another attempt.
BadCertificateUntrustedClassify status codes before retrying, as above. Configuration errors need an operator, not another attempt.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.