Problem Overview
An S7-1500 OPC UA server, when paired with a client such as Ignition 8.3.1, can return ExtensionObject values that the Milo-based OPC UA stack cannot decode. The symptom is a tag that previously subscribed cleanly and rendered as a JSON struct in Ignition, suddenly appearing as an unreadable scalar or throwing a logged serialization fault. Existing PLC tags continue to work; only new tags, recently modified tags, or tags whose DB hosting was moved (for example Instance DB → Global DB) start to misbehave.
The error chain from the Ignition gateway log typically reads:
Error decoding ExtensionObject: ExtensionObject[body=ByteString[bytes=000000000000000000000000],
encodingId=NodeId{ns=3, id=TE_"misc"."Data"}]
org.eclipse.milo.opcua.stack.core.UaSerializationException:
no codec registered for encodingId=ns=3;s=TE_"misc"."Data"
at org.eclipse.milo.opcua.stack.core.encoding.binary.OpcUaDefaultBinaryEncoding.decode(OpcUaDefaultBinaryEncoding.java:89)
at org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject.lambda$decode$0(ExtensionObject.java:116)
at com.inductiveautomation.ignition.gateway.opcua.OpcUaToIgnition.decodeExtensionObject(OpcUaConversions.kt:680)
at com.inductiveautomation.ignition.gateway.opcua.OpcUaSubscriptionListener.onDataReceived(OpcUaSubscriptionManager.kt:506)
The controlling identifier is encodingId=ns=3;s=TE_"misc"."Data". Namespace 3 is the SIMATIC namespace injected by the S7-1500 OPC UA server, and the TE_ prefix indicates a TypeEncoding node that refers to a structured data type defined in the PLC's companion namespace. When the Milo stack has no codec registered for that encoding ID, the body remains an opaque ByteString of zeros (length 10, two-byte length prefix + eight-byte empty payload) and the subscription update fails to convert into a usable Ignition qualified value.
Root Cause Analysis
The S7-1500 OPC UA server exposes struct (UDT) data through two parallel mechanisms:
- The legacy DataType Dictionary (sometimes called "Deprecated DataType Dictionary Support"), which uses a single combined TypeDictionary node with binary-encoded descriptions.
- The modern DataTypeDefinition attribute on the
DataTypenode itself, which encodes structure metadata directly on the type node.
When the PLC is configured to expose its types via the legacy DataType Dictionary path and the dictionary binary blob does not match the structure the client has cached, the encoding ID resolves but the stack cannot bind a decoder. The fault is therefore not a transport or authentication failure; it is a metadata consistency failure between the S7-1500 server's ns=3 type tree and what the client (Ignition) was led to expect at subscription time.
Three conditions on the PLC side reliably reproduce this symptom class:
- A struct/UDT is edited in TIA Portal (member added, removed, renamed, reordered, or initial value changed) and the project is downloaded to the CPU while the OPC UA session is still open. The auto-reconnect does not always force a re-read of the dictionary.
- A UDT that previously lived in an Instance DB (IDB) is moved into a Global DB (or vice versa) and downloaded. The encoding node ID path changes from
TE_"DB_name"."StructName"toTE_"misc"."Data"or back, invalidating cached codecs. - Optimized block access is toggled on the affected DB, which changes the SIMATIC byte layout and the OPC UA structure description.
On the Ignition side, the relevant flag is the advanced OPC UA connection setting Deprecated DataType Dictionary Support. By default, this setting is true only on connections that were upgraded from Ignition 8.1.x; new connections in 8.3.x default to false. With the flag enabled, Ignition attempts to use the SIMATIC dictionary path, and any mismatch yields the codec exception above.
Affected Configurations and Versions
| Component | Verified Versions | Notes |
|---|---|---|
| SIMATIC S7-1500 / S7-1500T CPU firmware | V2.9 → V20 (TIA Portal V17–V20) | TypeDictionary behavior set per OPC UA server interface in Properties → OPC UA → Server. |
| TIA Portal OPC UA companion namespace | Companion spec namespace 3 (SIMATIC) | Defines UDT encoding IDs prefixed TE_. |
| Inductive Automation Ignition | 8.1.x → 8.3.1 (Milo stack 0.6.x) | Deprecated DataType Dictionary Support flag introduced at 8.1.27. |
| OPC UA client (verification) | UaExpert 1.7+, Prosys OPC UA Browser | Used to confirm DataTypeDefinition attributes. |
SIMATIC to OPC UA Data Type Mapping
SIMATIC data types do not map one-to-one to OPC UA built-ins. The PLC exposes a hybrid representation that includes SIMATIC-specific scalar and structure types in namespace 3. Use the mapping below to validate what the server should publish for each PLC-side declaration.
| SIMATIC type (TIA) | OPC UA type | Encoding node prefix | Notes |
|---|---|---|---|
| BOOL | Boolean | — | Direct mapping, no struct wrapper. |
| INT / DINT / LINT | Int16 / Int32 / Int64 | — | Signed integer mapping; check endianness on optimized DBs. |
| REAL / LREAL | Float / Double | — | IEEE-754; verify byte order after TIA download. |
| STRING (UTF-8 max 254) | String | — | Length prefix in OPC UA includes NUL terminator. |
| WSTRING | String | — | UTF-16; ensure client reads in UTF-16 mode. |
| DTL | ExtensionObject (custom) | TE_"misc"."DTL" |
First struct type commonly affected by codec failures. |
| UDT (PLC-side type) | Structure DataType (ns=3) |
TE_"<DB>"."<UDT>" or TE_"misc"."Data"
|
Encoding path changes when UDT moves between DBs. |
| ARRAY[..] OF <type> | Structure or Array, depending on layout | Per element | Optimized block access may collapse inner layout. |
| STRUCT (non-UDT) | Structure DataType | TE_"<DB_name>"."StructName" |
Encoding ID includes DB name; renaming DB invalidates the codec. |
Per Siemens documentation, the S7-1500 OPC UA server is required to publish all SIMATIC types in the SIMATIC companion namespace so that clients can resolve them; only OPC UA built-ins are reused without conversion. See Mapping SIMATIC data types to OPC UA data types (S7-1500 / S7-1500T) for the full matrix.
Diagnostic Procedure
Follow this sequence before making any change to isolate whether the fault is on the PLC side, the Ignition side, or both.
-
Enable the Milo debug logger on Ignition. In the Gateway Webpage, navigate to Status → Diagnostics → Logs and set the logger
opcua.gateway.OpcUaConversionstoDEBUG. This surfaces the exact encoding ID, namespace URI, and body length for every ExtensionObject that the stack rejects. Reference: Changing Logging Levels — Ignition User Manual. -
Inspect the address space with UaExpert. Connect to the same OPC UA endpoint used by Ignition and browse Types → DataTypes. Open the offending node (for example
ns=3;s=TE_"misc"."Data") and verify:- The
DataTypeDefinitionattribute is populated (Structure subtype with field list). - The
Encodingreference resolves to aBinaryEncodingnode whoseTypeIdpoints to a node that the client can decode. - The structure field count and order match the TIA Portal UDT definition.
- The
-
Compare server export with PLC definition. In TIA Portal, open Properties → OPC UA → Server → Export and export the server interface XML. Verify that every
UADataTypewith aTE_prefix has a matching definition in the running CPU project. - Check namespace URI binding. In Ignition, open the OPC UA Connection → Edit → Servers → Endpoints and confirm that the namespace 3 URI exposed by the server matches what TIA Portal reports under OPC UA → Server → Namespaces. A mismatch indicates the CPU was loaded with a different project than the one TIA Portal is editing.
- Reproduce the fault deterministically. Note the timestamp of the first failing subscription update. Cross-reference it with the TIA Portal download history on the CPU's online backup. Any download event within ±60 s is suspect.
Resolution Steps
Fix 1 — Disable Deprecated DataType Dictionary Support in Ignition
- Open Config → OPC UA → Connections in the Gateway Webpage and select the affected Siemens connection.
- Click Edit, then click More → Advanced Settings.
- Set Deprecated DataType Dictionary Support to
false. - Click Save. Ignition will drop and re-establish the underlying Milo session, forcing a fresh read of the
DataTypeDefinitionattributes. - Wait for the connection status to return to Connected and verify that the previously failing tags now resolve as JSON structs.
Fix 2 — Move UDTs to Global DBs or Re-publish TypeDictionary
- In TIA Portal, declare a Global DB of the same UDT type and copy the data block content into it.
- Download only the hardware/software changes to the CPU (do not perform a full recompile if avoidable).
- In the OPC UA server properties, disable the Optimized block access attribute on the new Global DB if the UDT contains
STRING,WSTRING, or arrays of structs. Optimized access changes byte alignment, which the S7-1500 OPC UA server reflects in theDataTypeDefinitionand may still desynchronize the client. - In Ignition, force a reconnect: open the OPC UA connection, click Edit, change the description by one character, Save. The reconnection will pull fresh type metadata.
Fix 3 — Server-side TypeDictionary Reset
- In TIA Portal, open Device Configuration → Properties → OPC UA → Server → Data access.
- Uncheck Use type dictionary (also called "Support deprecated DataTypeDictionary"). This forces the S7-1500 OPC UA server to expose only the modern
DataTypeDefinitionattributes. - Compile and download to the CPU.
- Cycle the OPC UA server on the CPU: Online → Accessible devices → CPU → Online & Diagnostics → OPC UA → Stop, then Start. This invalidates all sessions.
- Reconnect from Ignition; the Milo stack will rebuild codecs against the new
DataTypeDefinitiontree.
Fix 4 — Compensating Client Workaround (when server cannot be touched)
If the PLC is on a production line and cannot be re-downloaded, force Ignition to re-resolve codecs without restarting the Gateway:
- Disable the OPC UA connection in the Gateway Webpage.
- Wait 5 seconds for in-flight subscriptions to release.
- Re-enable the connection. The session is re-keyed and all type metadata is re-read.
- If the fault returns within minutes, the PLC server is publishing a self-inconsistent dictionary; only a server-side fix will hold.
Verification
After applying any fix above, confirm the resolution with the following checks:
- In the Ignition Designer, drag the previously failing tag onto a window. It should expand into a struct with named members rather than showing as an unreadable byte string.
- In the Ignition Gateway logs, search for
UaSerializationException. The count should drop to zero within one publish interval (default 1 s). - In UaExpert, subscribe to the same tag at 250 ms and verify stable values for at least 5 minutes. A return of
Bad_DecodingErrorindicates the server is still publishing mismatched metadata. - From the OPC UA client perspective, run Tools → Discover and confirm the
DataTypeDefinitionattribute on the encoding node resolves without aBad_AttributeIdInvalidstatus code. - If your project uses Ignition Tag History on these structs, verify that historical records populate without null values.
Prevention Checklist
| Phase | Action | Effect |
|---|---|---|
| TIA Portal project design | Place UDTs in Global DBs, not Instance DBs. | Stabilizes encoding node IDs across DB renaming. |
| TIA Portal project design | Disable "Optimized block access" on any DB containing STRING/WSTRING or nested structs consumed by OPC UA. | Prevents byte-alignment-induced dictionary drift. |
| TIA Portal project design | Disable the legacy TypeDictionary option unless an external client requires it. | Eliminates the ns=3 dictionary failure path entirely. |
| Ignition connection setup | Set "Deprecated DataType Dictionary Support" to false on every new S7-1500 connection. |
Routes decoding through DataTypeDefinition, the supported path. |
| Change management | After any TIA Portal download that touches a DB used by OPC UA, force an Ignition reconnect. | Refreshes cached codecs before a stale read corrupts history. |
| Monitoring | Add a Gateway log alarm on UaSerializationException. |
Catches the failure class before a historian loses data. |
Related Error Codes and Stack Traces
| Code / Identifier | Origin | Meaning |
|---|---|---|
Bad_DecodingError (0x80080000) |
OPC UA status code | Server body cannot be decoded with any registered binary codec. |
Bad_AttributeIdInvalid (0x80050000) |
OPC UA status code | Server lacks DataTypeDefinition attribute on the type node. |
16#8005_0000 (S7-1500 client-side, SFB / FB usage) |
Siemens S7-1500 OPC UA client instruction | Reports a transport-level OPC UA fault returned from the remote server; not the same root cause but commonly searched together. Reference: Errors during the communication through an OPC UA Server from a 1515F-2 PLC (client). |
no codec registered for encodingId=ns=3;s=... |
Milo stack | Ignition-side manifestation of the same fault; verify the encoding ID against the live server namespace. |
Cross-Platform Notes
The S7-1500 OPC UA server's namespace 3 + TE_ encoding scheme is not specific to Ignition. Any Milo-based client (including open-source libraries built on Eclipse Milo) and any .NET Standard stack tracking the OPC Foundation reference implementation will hit the same no codec registered exception under identical conditions. The .NET ecosystem has tracked equivalent issues on the OPC Foundation tracker, for example UA-.NETStandard issue #1066. Likewise, when an S7-1500 acts as the OPC UA client against a third-party server, the corresponding Siemens-side symptom appears in the diagnostic buffer of the OPC UA client instruction block; see OPC UA connection problem — S7-1500 client for an OMRON NX102 case study.
FAQ
Why do existing tags keep working after a TIA download but new tags break?
The Milo stack caches the decoder for each encoding ID the first time it decodes a value. Existing tags are still bound to the original codec; new tags encounter the post-download encoding node, which no longer matches the cached definition. A forced reconnect clears the cache.
Does "Deprecated DataType Dictionary Support = false" apply to all S7-1500 connections?
Yes, the toggle is per OPC UA connection in Ignition. Set it to false on every Siemens connection, whether the connection was created in 8.1.x or 8.3.x, to avoid the legacy dictionary path entirely.
What is the difference between Optimized and Non-Optimized block access for OPC UA structs?
Optimized access lets the S7-1500 reorder members in memory for performance and uses symbolic addressing only; non-optimized access preserves the declared byte layout. OPC UA publishes the layout it sees, so toggling the setting changes the DataTypeDefinition field offsets and will desynchronize cached client codecs.
Does moving a UDT from an Instance DB to a Global DB change the encoding node ID?
Yes. An Instance DB embeds the UDT under TE_"<DB_name>"."StructName", while a Global DB exposes it under a shared TE_"misc"."Data" or type-name reference. Any client holding the old encoding ID will fail until it reconnects and rebinds.
Can the OPC UA server on the S7-1500 be restarted without stopping the PLC?
Yes. In TIA Portal Online & Diagnostics, navigate to OPC UA → Stop/Start or use the web server of the CPU if enabled. The PLC scan continues; only OPC UA sessions are dropped and re-established.