Resolving BadNoMatch 0x806F0000 on Siemens S7 Array BrowsePath

David Krause14 min read
OPC / OPC UASiemensTroubleshooting
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

1. Problem Definition

The OPC UA client receives the standard service result BadNoMatch with the symbolic identifier StatusCode_BadNoMatch and the numeric value 0x806F0000 (decimal 2,154,758,144) when it calls the TranslateBrowsePathsToNodeIds service against a Siemens SIMATIC S7-1500/S7-1200 OPC UA Server. The failure is repeatable, isolated to array element nodes, and is independent of the OPC UA client stack (QuickOPC, .NET Standard UA SDK, open62541, Eclipse Milo, Siemens OPC UA Client Example).

Symptom signature. Translate succeeds for scalar variables, structured (UDT) members, and the parent array container, but fails for individual array elements such as DATA.ArrUDT_Counters[0], DATA.ArrUDT_Counters[1], etc. The same path returns a syntactically malformed NodeId (ns=3;s="DATA"."ArrUDT_Counters"[[0]]) when the server does respond with success under specific configurations, containing a duplicated bracket pair that is rejected by downstream clients.

Failure manifest in client logs (QuickOPC 2023.x and later):

OPC-UA service result - An error specific to OPC-UA service occurred.
---- SERVICE RESULT ----
StatusCode: {BadNoMatch} = 0x806F0000 (2154758144)
Service: TranslateBrowsePathsToNodeIds
StartingNode: ns=3;s="DATA"
RelativePathElement[0]:
  TargetName  : 0
  ReferenceTypeId: i=33 (Aggregates)
  IsInverse   : false
  IncludeSubtypes: true

2. OPC UA TranslateBrowsePathsToNodeIds Service Specification

The TranslateBrowsePathsToNodeIds service is defined in OPC UA Part 4 (Services), Section 5.7.5. It accepts a list of BrowsePath structures, each consisting of a startingNode (of type ExpandedNodeId) and a sequence of RelativePathElement. Each RelativePathElement carries a targetName (QualifiedName with namespace index and name), a referenceTypeId, an isInverse flag, and an includeSubtypes flag.

Parameter Type Description
startingNode ExpandedNodeId Node where path resolution begins. Must be local to the server.
relativePath RelativePath Array of RelativePathElement describing the traversal.
targetName QualifiedName BrowseName of the target, encoded as (namespaceIndex, name).
referenceTypeId NodeId Hierarchical reference to follow (e.g. i=33 Aggregates, i=32 HasProperty, i=35 HasComponent).
isInverse Boolean True if the reference is followed in the reverse direction.
includeSubtypes Boolean True if subtypes of the reference type are acceptable.

The service specification permits servers to return any of the standard Bad_ status codes defined in OPC UA Part 4. BadNoMatch is returned when the server cannot find a target for the supplied path. According to the specification, this indicates the path itself is not navigable from the supplied starting node, not necessarily that the path is malformed.

2.1 Status Code Encoding

OPC UA status codes use a 32-bit structure consisting of three sub-fields:

Bits 31:30  Severity (00 = Good, 01 = Uncertain, 10 = Bad, 11 = Reserved)
Bits 29:28  Sub-Code (00 = not used)
Bits 27:16  Reserved / Structure Field
Bits 15:0   Info-Code (the specific status identifier)

For BadNoMatch = 0x806F0000:

Field Value Meaning
Severity 10b Bad
Sub-code 00b Diagnostic level (not a structure result)
Info-Code 0x6F00 BadNoMatch (per Part 6)

3. BadNoMatch Reference Details

The BadNoMatch status code is documented in OPC UA Part 4 (Services), Appendix A with the following description:

"The path specified cannot be followed. The path may be too old or the server may not be able to follow it. The path may be missing a starting node, or the path may be invalid for the current view."

Additional supplementary status codes that may accompany a failed translation:

StatusCode Hex Dec Meaning
BadNodeIdUnknown 0x80340000 2151677952 StartingNode is not known to server
BadNodeIdInvalid 0x80330000 2151677952 StartingNode format invalid
BadNothingToDo 0x80070000 2147614720 Empty paths array submitted
BadTooManyOperations 0x80110000 2148728832 Server limits on path count
BadQueryTooComplex 0x80680000 2154692608 Server cannot process the query
BadNoMatch 0x806F0000 2154758144 Path not navigable from start node

Per Part 4, when a server returns BadNoMatch, the entire operation fails with a single status. The server shall not return partial results when at least one path cannot be resolved, unless OperationLimits are exceeded.

4. Siemens SIMATIC S7 OPC UA Server Array Behavior

The SIMATIC S7-1500 OPC UA server (built into TIA Portal V15.1 and later) implements arrays of structured types (UDTs) by generating a parent node that holds the array metadata and one child node per element. These element nodes are addressable via the standard OPC UA reference HasComponent (i=47) or, in some firmware versions, the legacy Aggregates (i=33) reference.

4.1 Array Node Hierarchy

For an S7 declaration of ArrUDT_Counters : ARRAY[0..9] OF UDT_Counter under the data block DATA, the generated address space is:

ns=3;s="DATA"
  └── ns=3;s="DATA"."ArrUDT_Counters"        (parent array, ValueRank=1, ArrayDimensions=[10])
        ├── ns=3;s="DATA"."ArrUDT_Counters"[0]
        ├── ns=3;s="DATA"."ArrUDT_Counters"[1]
        ├── ...
        └── ns=3;s="DATA"."ArrUDT_Counters"[9]

Each element node carries a BrowseName identical to its DisplayName, both formatted as the bracketed index string ([0], [1], etc.) in the OPC UA namespace used by the S7 project (commonly ns=3 with the URI http://www.siemens.com/simatic-s7-opcua).

4.2 Firmware and TIA Portal Versions Affected

Per Siemens Industry Online Support, the issue is observable on S7-1500 CPU firmware V2.6 through V3.1 paired with TIA Portal V17 / V18 project exports. The vendor-provided sample client (KB entry 109737901) demonstrates the same translation failure when invoked against a representative configuration, indicating that the server is the authoritative source of the path resolution and returns a translated NodeId containing the malformed double-bracket suffix [[0]] when the call succeeds at all. The malformed NodeId is non-conformant with OPC UA Part 3 string-NodeId encoding rules and is rejected by any compliant client parser.

Siemens KB reference. Vendor diagnostic sample: Siemens OPC UA Client sample - TranslateBrowsePathsToNodeIds (Article ID 109737901).

5. UABrowsePath Construction and the Client-Side Pipe

On the client side, browse paths are typically constructed in three sequential stages when using a high-level wrapper such as QuickOPC, Prosys SDK, or a custom UA .NET application:

  1. Browse path composition. The browsing dialog or walker accumulates RelativePathElement objects starting from a chosen starting node, each carrying the resolved QualifiedName and the most specific reference type observed during the Browse service call.
  2. Descriptor binding. When the developer selects a target node from the UI, the path is associated with the UANodeDescriptor (or equivalent). For non-NodeId descriptors, the client stack converts the UABrowsePath object into the wire-format BrowsePath when the Translate service is invoked.
  3. Wire translation. The client invokes TranslateBrowsePathsToNodeIds against the server. The server walks the starting node, follows the reference chain using the supplied reference type IDs and target names, and returns either the matching NodeId or a status code such as BadNoMatch.

The UABrowsePath internal representation stores each element as a QualifiedName (namespace index + name) and a NodeId for the reference type. The ToString() override deliberately omits the namespace URI prefix and other metadata, marking the result with an asterisk (*) in the browse dialog to indicate that the displayed string is not the unambiguous canonical form.

5.1 Why the Heuristic Browse Path Can Be Ambiguous

Two design choices in the path composition logic can introduce ambiguity:

  • Choosing the most specific reference type seen during Browse, instead of the most generic valid hierarchical type (e.g. HierarchicalReferences, i=33) — leading to narrower filters on the server side.
  • Treating the BrowseName literal as a single token, when in fact OPC UA Part 3 mandates that QualifiedName consists of both a namespace index and a name string.

These factors matter less for scalar nodes (where the Browse service returns HasProperty or HasComponent consistently across the S7 server's address space) and significantly more for array element nodes, where the reference type chosen during Browse may not be the one the Translate server implementation accepts.

6. Root Cause Analysis

The root cause is the SIMATIC S7 OPC UA server's TranslateBrowsePathsToNodeIds implementation not recognizing the path constructed by client stacks for array element nodes. The combination of factors:

  1. The server's internal array element addressing logic expects either a direct NodeId string format (e.g. "DATA"."ArrUDT_Counters"[0]) or a different traversal rule than what the client sends.
  2. The reference type filter Aggregates (i=33) is recognized on Browse but is not accepted as a valid hierarchical filter on Translate for array elements in the affected firmware versions.
  3. When the server does return a successful translation, the resulting NodeId contains a duplicated bracket ([[0]]) that does not parse as a valid string NodeId per OPC UA Part 6 encoding rules.

Reducing the reference type filter to a broader hierarchical class (such as accepting all subtypes of HierarchicalReferences) does not resolve the issue, indicating the failure is at the path-element (targetName) matching level, not the reference type level.

Client Compose BrowsePath ReferenceType = Aggregates (i=33) Translate Service on SIMATIC S7 BadNoMatch 0x806F0000 Fallback: Hierarchical ReferenceType (broader) Translate Service still fails BadNoMatch 0x806F0000 Fallback: Direct NodeId ns=3;s="DATA"...[0] ReadAttribute/Read no Translate required Good 0x00000000

7. Live Mapping Code Patterns in QuickOPC

In QuickOPC's Live Mapping model (and equivalent tools such as the Prosys OPC UA Mapper or the Eclipse Milo Codegen), each mapped property is decorated with attributes that drive server discovery. The relevant attributes are:

Attribute Applies To Purpose
UAData Property Marks the property as a data source/target.
UANode(BrowsePath=...) Property Provides a string BrowsePath relative to the parent mapped node.
UANode(NodeId=...) Property Provides an absolute NodeId (string form).
UANodeIdAttribute Property Binds a NodeId expression to the property.
UANodeIdTemplate Property Templated NodeId with substitution variables.

7.1 Mapping a Whole Array (Workaround A)

Mapping the parent array (not the individual elements) returns the full array, but as an array of ExtensionObject instances for arrays of structured types. This is functional but requires a downstream decoder step to unpack each UDT payload.

using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.LiveMapping;

public class DT_DATA : DisplayData
{
    [UAData]
    [UANode(
        BrowsePath = ".ArrUDT_Counters",
        NodeId     = "nsu=http://www.siemens.com/simatic-s7-opcua;ns=3;s=\"DATA\".\"ArrUDT_Counters\"")]
    ]
    public object[] ArrUDT_CountersObject { get; set; }

    // Scalar members continue to work as before
    [UAData]
    [UANode(BrowsePath = ".SomeScalar")]
    public int SomeScalar { get; set; }
}
ExtensionObject consequence. Each array element is delivered as an OPC UA ExtensionObject whose Body is either a ByteString (default encoding) or a XmlElement. Decoding requires the S7 UDT schema (TypeId = ns=3;i=<UDT NodeId>) and a registered decoder. Plan for an additional decode pipeline step (e.g. UAExtensionObject.ToUAObject<T>() with a registered IUAEncoder) in your integration code.

7.2 NodeId Template Approach (Workaround B)

For arrays of simple types (Int32, Float, String), a NodeId template string that substitutes the element index can be used. The substitution variable $(BrowseName) carries the bracketed index literal:

// On the parent (mapping the array as a whole):
[UANode(NodeId = "nsu=http://www.siemens.com/simatic-s7-opcua;ns=3;s=\"DATA\".\"ArrUDT_Counters\"")]

// On an indexed child (using a template):
[UAData]
[UANodeIdTemplate("$(ParentNodeID)[$(BrowseName)]")]
public int CounterElement { get; set; }

This approach relies on the client stack concatenating the parent NodeId and the bracketed index to form a valid string NodeId. The dotted prefix in the BrowseName (e.g. DATA.ArrUDT_Counters) must be stripped; if the runtime cannot strip the prefix automatically, work around it by composing the template with explicit literals instead of $(BrowseName).

8. Diagnostic Procedure

The following procedure isolates whether the failure is client-side, network, or server-side, and captures the wire format needed for vendor escalation.

  1. Confirm scope. Attempt Translate on a known-good scalar node (e.g. DATA.SomeScalar) from the same starting node. If the scalar succeeds and the array element fails, the issue is array-element-specific on the server.
  2. Capture the wire trace. Use Wireshark with the OPC UA dissection plugin (Wireshark) or a UA-aware capture proxy such as OPC Foundation UA-NetStandard stack logger. Filter on the Opc.Ua Binary Protocol (port 4840 by default) and isolate the TranslateBrowsePathsToNodeIds request/response pair.
  3. Reproduce with the vendor sample. Download the Siemens OPC UA Client example from Siemens KB 109737901, configure the autologin to your CPU, and execute the array-element translation from that reference client. A failure here confirms server-side responsibility.
  4. Decode the BrowsePath encoding. In the request payload, locate the RelativePathElement entries. Confirm:
    • targetName.namespaceIndex matches the namespace index of the array's parent BrowseName (commonly 3 for SIMATIC S7).
    • targetName.name is the bracketed index string (e.g. [0]) and not a stripped or normalized variant.
    • referenceTypeId is a hierarchical reference (i=33 Aggregates or i=47 HasComponent) with includeSubtypes = true.
  5. Inspect the response. If the server returns a translated NodeId, validate it against the OPC UA Part 6 string-NodeId grammar. A result such as ns=3;s="DATA"."ArrUDT_Counters"[[0]] is malformed and indicates a server-side concatenation bug.
  6. Test broader reference types. Submit the same BrowsePath with referenceTypeId = i=33 and includeSubtypes = true, then again with referenceTypeId = null and includeSubtypes = false. Persistent failure indicates the issue is at the targetName matching layer, not the reference filter.

9. Workaround Decision Matrix

Scenario Recommended Workaround Trade-off
Arrays of simple types (Int32, Float, Boolean, String) Direct NodeId template "ns=3;s="DATA"."ArrX"[$(Index)]" Bypasses Translate entirely; static per element.
Arrays of structured types (UDT) Map parent array as object[]; decode ExtensionObject payloads downstream Requires UDT schema registration and decoder.
Dynamic index discovery required at runtime Use Browse service to enumerate child BrowseNames, then construct direct NodeIds manually Adds a Browse round-trip; still avoids Translate.
Read-only access, no subscription Use UAReadOnlyNodeId with explicit string NodeId No Live Mapping overhead.
Vendor patch not yet available Engage Siemens Industry Online Support with Wireshark capture and vendor sample reproduction Resolution time dependent on vendor response.

10. Verification

After applying a workaround, verify resolution with the following checks:

  1. Single-element Read. Execute a Read against the constructed NodeId (e.g. ns=3;s="DATA"."ArrUDT_Counters"[0]) using your client stack. A Good status with the expected ValueRank=0 scalar payload confirms the NodeId is valid.
  2. Subscribe/Monitor. Create a subscription on the same NodeId. Confirm the server returns MonitoredItemCreateResult with StatusCode = Good and the initial value notification arrives within the publishing interval (typically 100-1000 ms).
  3. Round-trip Translate. Once the server-side fix or firmware patch is applied, repeat the original Translate request with the same BrowsePath. Expect Good status and a NodeId matching the manually constructed one byte-for-byte.
  4. Boundary elements. Verify both index 0 and the highest index (e.g. [9] for an ARRAY[0..9]) succeed. S7 servers occasionally treat the first and last elements differently in array element generation.
  5. Reconnect after CPU restart. Confirm the NodeIds persist across a CPU STOP-to-RUN transition and a power cycle. SIMATIC S7 NodeIds are generally stable across restarts, but server-side fix paths should be re-validated after a firmware update.
Verification caveat. Even after applying the vendor patch, keep the manual NodeId fallback in your client code. The TranslateBrowsePathsToNodeIds path remains subject to server-side heuristics; a direct NodeId is the most robust addressing method for OPC UA arrays on SIMATIC S7.

11. Long-Term Resolution Path

For production systems where workaround A or B is not acceptable, escalate through Siemens Industry Online Support with the following package:

  • Wireshark capture of the failing Translate request/response (OPC UA binary, port 4840).
  • Output from the vendor sample client (KB 109737901) demonstrating the same failure against the same CPU.
  • TIA Portal project export (with UDTs anonymized if necessary) showing the array declaration and the generated namespace configuration.
  • CPU firmware version (read from TIA Portal > Online > Diagnostics > CPU Properties).
  • Screenshot of the malformed NodeId (if the server returns success with a malformed string).

Reference the KB article 109737901 in the support request to accelerate routing to the OPC UA server development team.

12. Cross-Platform and Cross-Stack Notes

The root cause is server-side and reproduces identically across OPC UA client stacks because the failure occurs in the server's TranslateBrowsePathsToNodeIds implementation. However, the user-visible impact and the available workarounds differ:

Stack Affected by Failure Direct NodeId Workaround Notes
QuickOPC (.NET) Yes Supported via UANodeIdAttribute / UANodeIdTemplate Template parsing limitations as noted in §7.2.
Eclipse Milo (Java) Yes Native NodeId construction No template parser required.
open62541 (C) Yes UA_NodeId_parse on string Lightweight, no descriptor layer.
Prosys SDK (Java/.NET) Yes UAIdentifier-based binding Similar to QuickOPC attribute model.
Siemens OPC UA Client sample Yes (demonstrates the issue) Hardcode NodeId strings Reference implementation.

13. FAQ

What is the OPC UA status code 0x806F0000 (BadNoMatch)?

BadNoMatch = 0x806F0000 (decimal 2,154,758,144) is a standard OPC UA Part 4 status code with severity Bad and Info-Code 0x6F00. The server returns it when the supplied BrowsePath cannot be followed from the given starting node — either the path is invalid or the server cannot navigate it.

Why does TranslateBrowsePathsToNodeIds fail only on S7 OPC UA array elements?

The SIMATIC S7-1500 OPC UA server (firmware V2.6 through V3.1) does not recognize the path elements generated by standard client stacks for array element nodes. The failure is reproducible with the Siemens vendor sample client (KB 109737901), confirming the issue is server-side in the path-element matching logic, not in the reference-type filter.

Can I work around BadNoMatch by mapping the parent array instead of individual elements?

Yes. Declaring the property as object[] with a NodeId pointing at the parent array (ns=3;s="DATA"."ArrUDT_Counters") returns the entire array in a single call. For arrays of structured types, each element is delivered as an ExtensionObject and requires UDT-aware decoding downstream.

What NodeId format should I use for SIMATIC S7 array element addressing?

Use the string-NodeId form with the bracketed index literal: nsu=http://www.siemens.com/simatic-s7-opcua;ns=3;s="DATA"."ArrUDT_Counters"[0]. The namespace URI is http://www.siemens.com/simatic-s7-opcua, the namespace index is typically 3, and the bracketed index must not be prefixed by a dot.

How do I capture OPC UA wire traffic for vendor escalation?

Use Wireshark with the built-in OPC UA Binary protocol dissector on port 4840 (default). Filter for the TranslateBrowsePathsToNodeIds service request/response pair, export the relevant packets, and attach the capture together with the CPU firmware version, TIA Portal project export, and the reproduction from Siemens KB 109737901 to your support request.

Back to blog