Status code · Channels

BadSecureChannelIdInvalid

BadLifecycle

BadSecureChannelIdInvalid means the SecureChannelId in your message header does not match any channel the server holds. It happens after a server restart, after the channel was closed, or when a client sends on a channel that belongs to a different connection. Open a fresh secure channel and re-establish the session.

Defined behaviour: The SecureChannelId is not valid - the identifier in the message header does not refer to a channel the server knows. (our description of the condition this code reports)

What you actually see

Requests are rejected instantly with a channel-level error, often immediately after a reconnect attempt that appeared to succeed at the TCP layer.

Why it happens

  • Server restarted and lost its channel tableSecureChannelIds are assigned by the server and held in memory. After a restart the client's cached id refers to nothing. If the client reconnected the socket but reused the old channel id, this is the exact failure you get.
  • Client sent on a channel it had already closedA shutdown path or an error handler closed the channel while requests were still queued. Those requests reach the server with a now-unknown id. The equivalent transport-level rejection is BadTcpSecureChannelUnknown.
  • Channel id used on the wrong socketA channel is bound to one transport connection. Multiplexing bugs, connection pooling, or a client that opens a second socket and reuses the first channel's id produce this immediately.
  • Token renewal handled incorrectlyDuring RenewSecureChannel the channel id stays the same but the token changes. A client that instead treats renewal as a new channel, or that mixes the ids of two overlapping channels, will address a channel the server does not have.
  • Load balancer sent the request to a different server instanceTwo servers behind one virtual address each keep their own channel table. Once a request lands on the instance that did not create the channel, the id is unknown there even though the client is perfectly correct.

How to fix it

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

  1. Check whether the server restartedRead Server_ServerStatus_StartTime after reconnecting, or check the server log. A restart makes this expected and moves the question to whether your client discards cached channel state properly.
  2. Prove there is exactly one server instance behind the endpoint URLResolve the hostname and compare the ApplicationUri and server certificate thumbprint across several connections. Different values from the same URL mean a load balancer or a DNS round-robin is splitting your channels.
  3. Discard all cached channel state on any channel errorOn BadSecureChannelIdInvalid, BadSecureChannelClosed or BadTcpSecureChannelUnknown, drop the channel id, the token and the derived keys, then open a new channel from scratch. Never retry the same request on the old id.
  4. Verify renewal keeps one channel identityCapture the handshake with the Wireshark OPC UA dissector and confirm OpenSecureChannel with request type Renew keeps the same SecureChannelId while issuing a new token.
  5. Re-establish the session on the new channelAfter the new channel is up, re-bind or recreate the session and then call TransferSubscriptions. If your stack cannot re-bind, recreate the session and accept the cost.

Where it shows up, by tool and stack

Tool / stackWhat to do there
UA-.NETStandard (C#)The channel is owned by the transport channel object, not by the Session; disposing and recreating the channel is the correct response. Enable Utils tracing for the SecureChannel category to see id and token transitions.
open62541 (C)The client tracks the channel in UA_SecureChannel with its own state enum. Errors here surface through the connect status; do not attempt to reuse a channel after any secure-channel-level error.
node-opcuaClientSecureChannelLayer manages the id and token renewal. If you see this code, check whether application code is creating more than one channel against the same endpoint.
KubernetesExposing an OPC UA server through a Service with more than one replica breaks channels this way. Use a StatefulSet with a stable per-pod endpoint, or one Service per replica, and never round-robin opc.tcp.
Wireshark OPC UA dissectorShows SecureChannelId and TokenId on every UASC message, which makes it straightforward to prove whether the client or the server lost track of the channel.

What it looks like in the log

Request rejected: BadSecureChannelIdInvalid (channelId=41)
Received message for unknown secure channel 41 from 10.20.3.15
Renewing secure channel 41: new tokenId issued, channelId unchanged

Confirm the fix

Reconnect and confirm a new OpenSecureChannel is issued and the new id is used on every subsequent message, with no further channel-level rejections over a sustained run.

Stop it happening again

Make channel state strictly disposable in client code, keep OPC UA endpoints pinned to a single server instance, and never place a round-robin load balancer in front of opc.tcp.

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