Python · recipe
Handle errors and reconnect in Python
Wrap the session in a loop that reconnects with backoff, and let asyncua try to transfer your subscriptions rather than rebuilding them. Branch on the status code you actually got: the specific code almost always names the real problem.
| Stack | asyncua (FreeOpcUa/opcua-asyncio) |
|---|---|
| Version | 2.0.1 |
The code
import asyncio
from asyncua import Client, ua
URL = "opc.tcp://opcua.umati.app:4840"
class Handler:
def datachange_notification(self, node, val, data):
print(node, val)
def status_change_notification(self, status):
print("subscription status changed:", status)
async def run_once():
async with Client(url=URL) as client:
client.session_timeout = 30000
sub = await client.create_subscription(1000, Handler())
await sub.subscribe_data_change(client.get_node("i=2258"))
while True:
await asyncio.sleep(1)
await client.check_connection() # raises when the session is gone
async def main():
delay = 1
while True:
try:
await run_once()
except (ua.UaStatusCodeError, ConnectionError, asyncio.TimeoutError) as e:
print(f"disconnected ({e}); retrying in {delay}s")
await asyncio.sleep(delay)
delay = min(delay * 2, 60) # backoff, and stagger across a fleet
else:
delay = 1
asyncio.run(main())
What it prints
i=2258 2026-09-08 03:45:00.102000
disconnected (BadSessionIdInvalid); retrying in 1s
i=2258 2026-09-08 03:45:14.331000
subscription status changed: StatusCode(Good)
Notes
- Exponential backoff with a cap, and jitter if you run many clients. Two hundred collectors reconnecting in lockstep after a network blip will take the server down more reliably than the blip did.
- `check_connection()` is how you notice a dead session promptly rather than waiting for a read to fail.
- On reconnect, prefer transferring subscriptions over recreating them. GoodSubscriptionTransferred is the success signal.
- Do not retry a certificate error. BadCertificateUntrusted will fail identically forever until someone changes a trust list: log it loudly and stop.
- Distinguish the three families: certificate and identity errors are configuration, BadTooMany* are capacity, and BadSessionIdInvalid or BadConnectionClosed are transient.
What breaks first
A client retries a permanent configuration error forever and floods the logs
Classify status codes before retrying. Certificate, identity and not-supported errors need a human; only transient transport and session errors deserve a retry.
BadCertificateUntrustedClassify status codes before retrying. Certificate, identity and not-supported errors need a human; only transient transport and session errors deserve a retry.
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.