OPC UA WarningKeepAliveLate: Troubleshooting Keepalives

Jason IP4 min read
Bosch RexrothOPC / OPC UATroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

WarningKeepAliveLate with BadCommunicationError indicates that the server reached a notification or keepalive deadline without an available Publish token. For the observed subscription, a 10-second empty-subscription response is inconsistent with the revised 5000 ms publishing interval and revised MaxKeepAliveCount of 1. The expected keepalive time is 5000 ms, not 10000 ms.

Interpret the late-subscription warning

An OPC UA client supplies Publish tokens by sending PublishRequests. After receiving a PublishResponse, the client normally sends another PublishRequest to replenish the queue. The server requires an available token when it needs to return changed data or an empty keepalive response. A late state therefore points to Publish-token starvation at the deadline; it does not by itself prove that the monitored data, network, client SDK, or server caused the shortage.

An empty subscription and a subscription containing unchanged or suspended items follow the same keepalive requirement. The server sends a PublishResponse when the publishing interval expires with data ready, or when the keepalive time expires without a notification.

Calculate the correct keepalive deadline

Revised setting Observed value Timing consequence
Publishing interval 5000 ms Evaluation occurs on each 5000 ms publishing cycle.
MaxKeepAliveCount 1 Keepalive time = 5000 ms × 1 = 5000 ms.
Observed empty-subscription response Every 10 seconds Later than the calculated 5000 ms keepalive deadline.

Do not add an extra publishing interval. The expression PublishingInterval + (PublishingInterval × KeepAliveCount) incorrectly produces 10000 ms. Use:

KeepAliveTime = RevisedPublishingInterval × RevisedMaxKeepAliveCount
KeepAliveTime = 5000 ms × 1 = 5000 ms

The subscription lifetime is at least three times the keepalive time in the supplied evidence, giving a minimum of 15 seconds for these revised values. Treat lifetime expiration separately from a late keepalive.

Identify which component owns the configuration

The frontend application calculated its request as follows:

MaxKeepAliveTime = session.WatchdogTimeout / 2.0
MaxKeepAliveTime = 10000 / 2.0 = 5000
MaxKeepAliveCount = MaxKeepAliveTime / PublishingInterval
MaxKeepAliveCount = 5000 / 5000 = 1

This calculation belongs to the application, not to the Unified Automation .NET Client SDK. The installed UnifiedAutomation.UaClient.dll version was 4.1.0.556, but that version does not establish ownership of the application’s calculation. The client only requests subscription settings; the server can revise them. Diagnose timing from the revised values returned by the server, not solely from requested values or frontend defaults.

Changing the frontend refresh rate, which maps to the publishing interval, from 5000 ms to 2000 ms produced a MaxKeepAliveCount of 2 under the application’s integer calculation and eliminated the reported warnings. This is an observed workaround, not proof that every count of 1 must fail.

Separate client starvation from server timing

The capture reportedly contained PublishRequests every 2 seconds for two other active subscriptions. That does not, by itself, show whether enough PublishRequests were queued when subscription 36 reached its deadline. Correlate requests, responses, subscription identifiers, and revised settings within one session.

A date-time item that changed continuously prevented the warning because the server always had data to publish. The evidence suggests a possible off-by-one keepalive behavior in the embedded Bosch Rexroth IndraMotion MLC L65 OPC UA server, but it does not conclusively establish that defect. The decisive comparison is whether the server returns data on the expected 5000 ms cycle yet delays an empty keepalive until 10 seconds while Publish tokens remain available.

Periodic server-status reads are independent of subscription keepalives and do not explain the 10-second PublishResponse interval.

Capture and verify the failing sequence

  1. Run the test with one client to remove competing client behavior from the trace.
  2. Record the client log and a packet capture over the same interval.
  3. Record both requested and revised publishing interval, keepalive count, and lifetime values. Use only revised values for the timing analysis.
  4. Test the same subscription first with one changing item and then with no items or an unchanged item.
  5. Confirm that the client keeps PublishRequests queued before every expected keepalive deadline.
  6. Compare the response timing with RevisedPublishingInterval × RevisedMaxKeepAliveCount. If tokens are available but the empty response occurs after that deadline, escalate the synchronized trace and revised settings to the server supplier.
  7. As an application-level workaround, set the refresh rate to 2000 ms and verify that the revised keepalive count is 2 and the warnings cease, matching the reported result.

Verification requires more than disappearance of the log entry: confirm that empty PublishResponses arrive at the calculated keepalive deadline, PublishRequests remain available, and revised values match the values used in the calculation.

FAQ

How is OPC UA keepalive time calculated?

Multiply the revised publishing interval by the revised maximum keepalive count. With 5000 ms and a count of 1, the keepalive time is 5000 ms, not 10000 ms.

Why does an empty OPC UA subscription show WarningKeepAliveLate?

An empty or unchanged subscription still requires an empty PublishResponse at the keepalive deadline. The warning indicates that the server reached that deadline without an available Publish token, although a server-side delay remains a hypothesis if the capture proves tokens were queued.

Does UnifiedAutomation.UaClient.dll calculate MaxKeepAliveCount?

Not in this case. The frontend application calculated the requested count as MaxKeepAliveTime / PublishingInterval; verify the server’s revised values because those values control the actual subscription timing.

Back to blog