Status code · Sessions

BadSessionIdInvalid

BadLifecycle

BadSessionIdInvalid means the server no longer recognises the SessionId in your request header: the session timed out, was closed, or the server restarted. Stop reusing the handle. Create and activate a new session, then try TransferSubscriptions before rebuilding subscriptions and monitored items from scratch.

Defined behaviour: The Session id is not valid - the server does not recognise the authentication token or SessionId supplied in the request header. (our description of the condition this code reports)

What you actually see

A client that has been reading happily for minutes or hours suddenly fails every service call with BadSessionIdInvalid, and keeps failing until it reconnects.

Why it happens

  • Session timeout expiredThe server discards a session when no request arrives inside the revised session timeout. Note that the server returns a RevisedSessionTimeout in the CreateSession response that may be much lower than what you requested, and many clients ignore it. A client with no outstanding Publish and no keep-alive read is silent traffic-wise, so the server times it out.
  • Server restarted or the OPC UA application was recycledSessions are in-memory state; SessionIds are not persisted across a restart. A PLC download, a service restart, or a container redeploy invalidates every SessionId. The client's TCP socket may even survive briefly, which is why the first symptom is a service fault rather than a socket error.
  • Idle TCP connection killed by a firewall or NAT devicePurdue-style layered networks often put an idle timer on TCP sessions. The socket disappears without a FIN reaching the client, keep-alives never arrive at the server, and the server ages the session out. The client only learns about it on its next request.
  • Session evicted because the server hit its session limitWhen MaxSessionCount is reached some servers evict the oldest or least active session rather than refusing new ones. A client that reconnects in a loop without closing its old sessions manufactures exactly this situation, since each retry orphans a session that still counts against the limit.
  • Client reused a stale handle after its own reconnectReconnect helpers create a fresh session under the covers. Application code holding the old session object, or a cached authentication token in a worker thread, keeps sending the dead SessionId. This shows up as a subset of operations failing while others succeed.

How to fix it

In diagnostic order: work down, do not skip ahead.

  1. Read the revised session timeout the server actually grantedLog the RevisedSessionTimeout from the CreateSession response, not the value you asked for. If the server capped 10 minutes down to 30 seconds, every timing assumption downstream is wrong.
  2. Make sure something keeps the session aliveKeep at least one Publish request outstanding, or issue a periodic Read of Server_ServerStatus_CurrentTime, at an interval comfortably shorter than the revised timeout. A common practical setting is a keep-alive interval around a third of the timeout so two consecutive losses are tolerated.
  3. Rule out a server restartRead Server_ServerStatus_StartTime and Server_ServerStatus_State. A StartTime later than your session's creation time means the server restarted and the session loss was unavoidable. Compare against the server's own log or the PLC download timestamp.
  4. Check the path for idle timeoutsOn a Linux client, ss -o state established '( dport = :4840 )' shows the keep-alive timers on the opc.tcp socket. If a firewall reaps idle connections, shorten the client keep-alive below that idle timer rather than lengthening the session timeout.
  5. Reconnect properly instead of retrying the dead sessionOn BadSessionIdInvalid, create a new session, activate it, then call TransferSubscriptions with the old subscription ids. Handle GoodSubscriptionTransferred, and only recreate subscriptions and monitored items if the transfer fails.
  6. Count your sessions on the serverBrowse Server_ServerDiagnostics_SessionsDiagnosticsSummary and compare the live session count with MaxSessionCount from the server configuration. Session leaks from crashed clients are common and self-inflicted.

Where it shows up, by tool and stack

Tool / stackWhat to do there
UA-.NETStandard (C#)SessionReconnectHandler exists precisely for this: it re-binds the session, or creates a new one, and attempts subscription transfer. Subscribe to Session.KeepAlive and act on the first missed keep-alive rather than waiting for the fault.
node-opcuaClientSession emits keepalive and keepalive_failure; the ClientSession's reconnection logic will recreate the session and re-establish subscriptions. Do not cache the session object in module scope across a reconnect.
asyncua (Python)Client.session_timeout is what you request; the server's revised value governs. asyncua runs an internal keep-alive task, but if your event loop is blocked by synchronous work the keep-alive is delayed and the session dies.
open62541 (C)Call UA_Client_run_iterate regularly - it drives both keep-alive and the state machine. A client that only calls services on demand and never iterates will lose the session. Watch the state callback for UA_SESSIONSTATE_CLOSED.
UaExpertShows the connection going red in the Project tree and logs the fault in the Log view. Reconnect via right-click Reconnect; if it succeeds immediately, the problem is session lifetime, not certificates or endpoints.
IgnitionThe OPC UA connection status cycles to Faulted then back to Connected. Check the session timeout on the device connection and the gateway log for repeated session recreation, which points at an idle-timeout device in the path.

What it looks like in the log

ServiceFault: BadSessionIdInvalid on Read - session is no longer known to the server
Session keep-alive stopped responding; state changed to Disconnected, attempting reconnect
TransferSubscriptions after reconnect returned GoodSubscriptionTransferred for 3 subscriptions

Confirm the fix

Leave the client idle for longer than the revised session timeout and confirm it stays connected, then read Server_ServerStatus_StartTime to prove the server did not restart underneath you.

Stop it happening again

Standardise one reconnect helper across the fleet that honours the revised timeout, keeps a Publish outstanding, and attempts TransferSubscriptions first. Alert on session recreation rate, not just on connection state.

Stuck on more than one of these? The troubleshooting clinic works through broken configurations end to end, on camera.

Troubleshooting clinic →

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.

Free download
OPC UA Status Code Diagnostic Tree
A 15-page diagnostic reference grouping every normative status code by what actually went wrong: with the first action for each, and the four questions that resolve most faults before you read a single code.
Get the free diagnostic tree →
Free, no course, no login