BadIndexRangeNoData
BadArrays
BadIndexRangeNoData means the IndexRange parsed correctly but selected nothing: the array is shorter than the range you asked for, or is currently empty. Read the array without a range to see its real length, then clamp the range to that length. Array lengths can change at runtime.
What you actually see
A ranged read that worked yesterday now returns BadIndexRangeNoData, usually after the underlying array shrank or the server restarted with an empty buffer.
Why it happens
- Array shorter than the range at this instantThe array length is a property of the value, not of the node declaration. A queue, a recipe list or a fault buffer can be shorter than the declared ArrayDimensions maximum. A range of 0:19 on a buffer that currently holds 5 entries selects nothing beyond the end and the server reports no data rather than a truncated result.
- Array is empty right nowA zero-length array is a perfectly valid value. Any range at all selects nothing from it. This is common at startup, immediately after a reset, or when the source device has not produced its first record.
- Declared ArrayDimensions taken as the guaranteed lengthArrayDimensions with a non-zero entry declares a maximum or fixed size in the model, but servers backed by dynamic sources often return fewer elements. Clients that size their range from ArrayDimensions rather than from the returned value hit this immediately.
- Range built from a stale cached lengthA client that reads the array length once at startup and reuses it for every subsequent ranged read will fail as soon as the source shrinks. Nothing notifies the client that the extent changed.
- Monitored item created with a range that later goes out of extentA monitored item carries its IndexRange for its lifetime. If the value shrinks below the range, the item starts reporting this status instead of values, and it will keep doing so until the array grows again or the item is recreated.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Read the node with no IndexRange and look at the actual lengthThe returned Variant carries the real element count. Compare it against both your range and the node's ArrayDimensions. If ArrayDimensions is larger than the value, the model declares a capacity, not a guarantee.
- Clamp the range to the observed lengthCompute the end index as the smaller of your requested end and length minus one, and skip the read entirely when the length is zero. Ranges are zero-based and inclusive, so the last valid index of a 5-element array is 4.
- Decide whether no data is an error in your applicationFor a fault buffer, an empty result is normal and should map to an empty list, not an alarm. For a fixed-size configuration array it is a genuine fault. Handle the two cases differently rather than treating every occurrence as a failure.
- Re-read the length periodically if the array is dynamicWhere the source has a companion length or count node, monitor that node and derive the range from it. Where it does not, do an unranged read on a slow cycle purely to track the extent, and use ranged reads for the fast path.
- Recreate monitored items after a length changeIf a subscription item started reporting this code and the array has since grown, delete and recreate the monitored item so the server re-evaluates the range against the new extent.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UaExpert | The Data Access View shows the status code per row, so a ranged item stuck on BadIndexRangeNoData is visible next to healthy items. Remove the range from the row and re-add it to see the full array length. |
| asyncua (Python) | Read without a range and use the returned list length to size subsequent ranged reads. asyncua returns the status inside the DataValue, so check the StatusCode rather than assuming an exception will be raised. |
| node-opcua | A ranged read returns a DataValue whose statusCode is BadIndexRangeNoData with a null value. Guard on statusCode.isGood() before touching dataValue.value.value, or you will read undefined. |
| UA-.NETStandard (C#) | StatusCode.IsBad on the returned DataValue is the check; the Value property is null. In a subscription the notification carries the same status, so a data change handler that only looks at Value will silently process nulls. |
| OPC Publisher | A published node with a range that goes out of extent emits a message with a Bad status rather than dropping the item. Downstream consumers that filter on status keep working; those that do not will see nulls in the payload. |
| Ignition | A tag bound to a ranged array subscription goes to a Bad quality overlay when the range empties. The tag does not fault permanently - it recovers as soon as the array grows back into range. |
What it looks like in the log
Read ns=2;s=FaultBuffer with IndexRange 0:19 returned BadIndexRangeNoData - value length 0
MonitoredItem 42 status changed to BadIndexRangeNoData
IndexRange 5:9 selects no elements from an array of length 3
Confirm the fix
Grow the source array past the requested range and confirm the same read returns data with a Good status without recreating the session. If it stays bad after the array has grown, the monitored item needs recreating.
Stop it happening again
Never derive an IndexRange from ArrayDimensions alone. Bind the range to a length or count node where the model provides one, and treat an empty selection as a normal state in the consumer rather than an exception.
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.