Status code · Address space

BadReferenceTypeIdInvalid

BadReferences

BadReferenceTypeIdInvalid means the NodeId you gave as a reference type filter is not a ReferenceType node in that server. Usually it is a hardcoded numeric id from a different server, a namespace index that shifted, or an ObjectType passed where a ReferenceType belongs. Resolve reference types by namespace URI and BrowseName.

Defined behaviour: The reference type identifier supplied does not refer to a ReferenceType node in the server. (our description of the condition this code reports)

What you actually see

A Browse or AddReferences call that works against one server fails against another, and the browse returns nothing rather than an empty result set.

Why it happens

  • Namespace index hardcoded and now wrongA custom reference type defined by a companion model or a vendor lives in that model's namespace. Namespace indices are assigned per server and are unstable across restarts and reconfiguration, so a stored NodeId with a literal index points somewhere else after a change. This is the single most common source of broken integrations generally, and it applies to reference types as much as to variables.
  • Reference type id copied from another serverStandard reference types have fixed numeric ids in namespace zero, but vendor and companion-model reference types do not. An id taken from a development server and put into configuration will not resolve on a production server that loaded its namespaces in a different order.
  • An ObjectType or other node passed as a reference typeThe Browse description's ReferenceTypeId must name a node whose NodeClass is ReferenceType. Passing an ObjectType, a Variable or an instance produces this code. It happens in code that resolves a name against the whole address space rather than filtering by NodeClass.
  • Reference type not present because the model was not loadedA server that does not implement a particular companion model has none of its reference types. A client written against the model will pass an id that is simply absent. The right response is capability detection rather than treating it as an error.
  • Custom reference type removed or renamed in a server upgradeVendor address spaces change between firmware versions, and a reference type present in one release can be absent or renumbered in the next. A client that stored ids rather than names breaks at the upgrade.

How to fix it

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

  1. Resolve reference types by namespace URI and BrowseName at connectRead the server's NamespaceArray, find the index for the namespace URI you need, and build the NodeId from that index. Store the namespace URI and the identifier in configuration, never the raw index. This is the correct pattern for every NodeId, not only reference types.
  2. Use the standard reference types where they sufficeHasComponent, HasProperty, Organizes, HasTypeDefinition, HasSubtype and HierarchicalReferences are in namespace zero with stable ids and are present on every server. Most traversal can be expressed with them plus IncludeSubtypes, which avoids the problem entirely.
  3. Set IncludeSubtypes rather than enumerating typesBrowsing with HierarchicalReferences and IncludeSubtypes true covers every hierarchical reference type including vendor ones you do not know about. That is usually what you want, and it is more robust than a list of specific types.
  4. Verify the NodeClass of the node you are passingRead the NodeClass attribute of the id before using it as a reference type filter. A one-attribute read at startup turns a puzzling browse failure into a clear message in your own logs.
  5. Detect model support instead of assuming itBrowse for the namespace URI in the NamespaceArray before using anything from that model. Where it is absent, take the degraded path deliberately rather than issuing calls that will fail.
  6. Watch for model change eventsWhere the server raises general model change notifications, subscribe to them and invalidate your cached NodeIds and namespace mapping. That covers the upgrade and reconfiguration cases without a restart.

Where it shows up, by tool and stack

Tool / stackWhat to do there
opcua-commanderIt accepts a NodeId written with the namespace URI rather than the index and resolves the index from the server's NamespaceArray at runtime, which is exactly the pattern to copy in your own client.
UA-.NETStandard (C#)Use the ReferenceTypeIds constants for standard types and build custom ones through the namespace table read from the server. Do not construct NodeIds from literal indices held in configuration.
asyncua (Python)get_namespace_index resolves a URI to an index at connect, and ua.ObjectIds carries the standard reference type ids. Combine the two rather than writing ns=3 anywhere.
node-opcuaresolveNodeId accepts symbolic names for standard types, and the namespace array is available after connect for custom ones. Both remove the hardcoded index.
open62541 (C)The standard reference type ids are available as constants; for custom types, read the namespace array and construct the NodeId with the resolved index at runtime.
UaExpertThe attribute pane shows a node's NodeClass and NodeId including its namespace index, which is the quickest way to confirm whether an id you are using is really a ReferenceType and in which namespace it lives.

What it looks like in the log

Browse failed: BadReferenceTypeIdInvalid for referenceTypeId ns=3;i=4002
NamespaceArray index for http://example.org/UA/Machine/ is 5, configuration expected 3
Node ns=4;i=1201 has NodeClass ObjectType; cannot be used as a reference type filter

Confirm the fix

Confirm the browse returns the references you expect with the resolved reference type, and confirm the namespace index you resolved matches the URI in the server's NamespaceArray rather than a stored value.

Stop it happening again

Store namespace URIs and identifiers in configuration and resolve indices at every connect, prefer standard reference types with IncludeSubtypes, check NodeClass before using an id as a type filter, and subscribe to model change notifications to invalidate caches.

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