BadRequestHeaderInvalid
BadProtocol
BadRequestHeaderInvalid means the server rejected the RequestHeader on your service call: a missing or wrong AuthenticationToken, an unusable Timestamp, a bad RequestHandle or TimeoutHint, or an AdditionalHeader it cannot decode. It usually indicates a hand-built request or a client and server disagreeing about encoding.
What you actually see
Every service call on an otherwise healthy channel fails with the same header error, including simple ones like Read, so the problem is clearly not the service payload.
Why it happens
- Wrong or missing AuthenticationTokenThe RequestHeader carries the session's authentication token. A client that sends a null token, a token from a different session, or a token after the session was closed will be rejected at the header. Some servers return this code where others return BadSessionIdInvalid.
- Timestamp far from the server's clockThe header Timestamp is a UtcTime. A client with badly wrong time - an embedded device with no RTC or NTP, or a container on a drifted host - can produce a header the server refuses. The same skew tends to produce certificate time errors too.
- Hand-assembled or mis-encoded requestsClients written against the binary encoding by hand, or generated code that gets field order or optional-field bits wrong, produce headers the server cannot decode. This is common the first time someone drives the OpenAPI or JSON surfaces directly.
- An AdditionalHeader the server does not supportThe header has an extensible AdditionalHeader field carried as an ExtensionObject. A client that populates it with a type the server does not know may be refused rather than having the field ignored.
- Unreasonable TimeoutHint or RequestHandle valuesA TimeoutHint of zero, or a nonsensical value, is handled inconsistently across servers - some substitute a default, some reject the header. Reused or zero RequestHandles similarly upset stricter implementations.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Check the session state before blaming the headerConfirm the session is created and activated and that you are sending its current authentication token. A stale token is the most likely cause and is easy to rule out by reconnecting cleanly.
- Compare clocksRead Server_ServerStatus_CurrentTime and compare with the client clock. Anything beyond a second or two of skew should be fixed with NTP before you investigate further.
- Capture the request and inspect the headerUse the Wireshark OPC UA dissector on port 4840 with security mode None, and read the decoded RequestHeader fields directly. This immediately distinguishes a bad token from a bad timestamp from an undecodable AdditionalHeader.
- Reproduce with a known-good clientRun the same operation from UaExpert or opcua-commander against the same endpoint. If the reference client succeeds, the defect is in your client's header construction, not in the server.
- Fill the header from your SDK, not by handLet the stack populate RequestHeader - token, timestamp, handle, TimeoutHint - and set only what you genuinely need. Leave AdditionalHeader empty unless a specific feature requires it.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UA-.NETStandard (C#) | SessionClient fills the RequestHeader for you. Seeing this code usually means custom code that builds RequestHeader objects itself, or a request issued on a session whose token has changed. |
| open62541 (C) | The high-level client fills the header in __UA_Client_Service. If you call the low-level async service API, you own the header - and a zeroed timestamp or missing token is the usual mistake. |
| node-opcua | The request builders populate the header from the session. If you construct request objects directly from the schema types, set requestHeader.authenticationToken and timestamp explicitly. |
| Compliance Test Tool (UACTT) | Header validation is exercised deliberately, so a server that accepts nonsense headers or rejects reasonable ones will show up in the base service tests. |
| Wireshark OPC UA dissector | The best tool for this code: it decodes RequestHeader field by field, so you can see the exact offending value rather than guessing. |
What it looks like in the log
Service request rejected: BadRequestHeaderInvalid
RequestHeader.authenticationToken is null or not recognized for channel 9
RequestHeader timestamp 2019-01-01T00:00:00Z differs from server time by more than the allowed window
Confirm the fix
Repeat the same service call and confirm a Good response, then run a capture and check that the header carries the current authentication token and a timestamp within a second of server time.
Stop it happening again
Use the SDK's generated service calls rather than hand-built requests, keep clocks synchronised across the fleet, and add a client-side self-test that reads server time at connect and warns on skew.
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.