Status code · Address space

BadNotFound

BadBrowse paths

BadNotFound is the generic search failure: a browse path element, a discovery lookup or a query found nothing. In day-to-day work it almost always comes from TranslateBrowsePathsToNodeIds, and the cause is almost always a BrowseName whose namespace is wrong or a path element that does not exist on this instance.

Defined behaviour: A requested item was not found, or a search operation ended without success. (our description of the condition this code reports)

What you actually see

One entry in a browse-path translation result is bad while the others resolve, or a whole path fails at a specific element that you can plainly see in the browse tree.

Why it happens

  • The BrowseName namespace is wrongA BrowseName is a QualifiedName: a namespace index plus a name. Companion specification browse names live in that specification's namespace, not in namespace 0. Writing the name without its namespace prefix means you are asking for a different QualifiedName that happens to look the same in a tree view. This is the dominant cause.
  • The element does not exist on this instanceOptional members of a type - anything with the Optional modelling rule - may simply not be instantiated on a given machine. The path is valid against the type and invalid against this instance, which is why it works on one server and fails on another of the same model.
  • The path element uses the wrong reference typeEach RelativePathElement names a ReferenceTypeId, whether subtypes are included, and whether the step is inverse. A component reached by HasComponent will not be found by a path element restricted to Organizes, and a Property needs HasProperty.
  • The starting node is not what you thinkTranslating from the wrong anchor - the type instead of the instance, the wrong machine in an array of identical ones, or the folder above the one you meant - fails at the first element even though every name in the path is spelled correctly.
  • Case or spelling drift between versionsBrowseNames are case sensitive, and vendors do adjust them between firmware releases. A path copied from documentation for a different version of a companion specification fails on a name that is nearly right.

How to fix it

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

  1. Browse one level at a time to the failing elementStart at your anchor and browse forward, reading BrowseName on each child including its namespace index. The level where your expected name is absent, or present with a different namespace, is the answer.
  2. Resolve the namespace indices for the names, not just for the NodeIdsRead NamespaceArray and map the companion specification URI to its current index, then build every QualifiedName in the path with that index. This is the same discipline that prevents BadNodeIdUnknown, applied to BrowseNames.
  3. Set ReferenceTypeId and IncludeSubtypes explicitlyFor a general walk down the hierarchy, use HierarchicalReferences with subtypes included. Restrict the reference type only where you deliberately want to exclude other kinds of children.
  4. Check the modelling rule before assuming a bugBrowse the type definition and look at whether the member is Mandatory or Optional. An Optional member that a vendor did not implement is a specification-conformant absence, and your client has to cope with it.
  5. Translate from a verified anchorConfirm the starting NodeId by reading its BrowseName and HasTypeDefinition first. Half of the paths that fail at element one are being translated from the wrong node entirely.

Where it shows up, by tool and stack

Tool / stackWhat to do there
UaExpertThe browse tree shows BrowseName with its namespace prefix in the Attributes pane. Comparing that against the QualifiedName your client builds resolves most of these in under a minute.
asyncua (Python)node.get_child accepts a list of qualified names such as 2:Identification and translates the path for you, so the namespace prefix is explicit and visible in code rather than implied.
node-opcuamakeBrowsePath builds the RelativePath from a string form with namespace prefixes. The per-path StatusCode comes back in the result array, so check each element rather than the service status.
open62541 (C)UA_Client_translateBrowsePathsToNodeIds takes the RelativePathElements explicitly, including reference type and inverse flag, which makes the reference-type mistake visible in the source.
umati Sample Serveropc.tcp://opcua.umati.app:4840 is a good place to practise: its machines follow published companion specifications, so you can verify that your browse paths resolve against a model you can read independently.
OPC PublisherBrowse-path based configuration is more durable than NodeId based configuration across controller changes, but only if the namespace of each name is specified rather than assumed.

What it looks like in the log

TranslateBrowsePathsToNodeIds result[0] = BadNotFound at element 2 (Identification)
QualifiedName 0:MachineryItemState not found; server exposes 2:MachineryItemState
Optional component ProductionStatistics is not present on this instance

Confirm the fix

Translate the corrected path and confirm every element resolves to exactly one target, then read a value through the resolved NodeId to prove it is the node you wanted.

Stop it happening again

Build browse paths from resolved namespace indices in code, keep a per-server record of which optional members exist, and re-validate paths after firmware upgrades rather than assuming a companion model is implemented identically everywhere.

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