Skip to content

hiroz typed and dynamic subscribers receive nothing from buffer-aware rmw_zenoh publishers #371

Closed

Description

@YuanYuYuan

Part of #370. Reported in #369 for a raw subscriber. The raw subscriber is #372.

Problem

A hiroz typed or dynamic subscriber on a buffer-typed topic declares a liveliness token without a backends: field. The rmw_zenoh publisher routes such a subscriber to <base>/_buf/<gid>. Hiroz never reads that key, so the subscriber receives nothing. It stays matched, and nothing logs an error. Messages without buffer fields are not affected.

Fixed by

Pull request What it does
#384 Adds BufferGroup { Auto, Cpu, Off } and with_buffer_group on the subscriber builder and the cache builder. The default in this PR is Off.
#387 Changes the default to Auto, so a subscriber joins without a code change. It also documents the access-control effect of the wider subscription.

The issue is fixed when both pull requests merge.

Mechanism

sequenceDiagram
    autonumber
    participant Sub as hiroz subscriber
    participant Z as Zenoh
    participant Pub as rmw_zenoh publisher
    Sub->>Z: declare token (no backends: field)
    Sub->>Z: subscribe to base key
    Z->>Pub: token appears
    Note over Pub: not a CPU-group member, so it counts as an accelerated subscriber
    Pub->>Z: put on base/_buf/gid
    Note over Sub: never subscribed to base/_buf/gid, receives nothing
    rect rgb(235, 245, 235)
    Note over Sub,Pub: with a joined subscriber
    Sub->>Z: declare token ending in backends:cpu:
    Sub->>Z: subscribe to base/**, keep the base key and base/_buf_cpu
    Pub->>Z: put on base/_buf_cpu
    Z->>Sub: every message
    end
Loading

Reproducer

Use a container with ros-lyrical-rmw-zenoh-cpp 0.10.6.

  1. Start the router: ros2 run rmw_zenoh_cpp rmw_zenohd.
  2. Start a publisher: ros2 topic pub -r 5 /cloud sensor_msgs/msg/PointCloud2 "{}".
  3. Start a hiroz typed subscriber on /cloud, built from main before the fix.
  4. Count the messages for 10 s.

Before and after

before with the shipped design
token of a typed subscriber on a message with an unbounded uint8[], such as PointCloud2 no backends: field ends in /backends:cpu:
token of a subscriber on a message that nests one, such as visualization_msgs/Marker no backends: field ends in /backends:cpu:
dynamic subscriber, with a schema set by with_dyn_schema no backends: field joins when the schema has an unbounded uint8[] or char[], directly or nested
subscriber with no message definition no backends: field joins, because hiroz cannot tell whether the topic carries buffers
cache subscriber no backends: field joins by the same rule, and with_buffer_group on the cache builder overrides it
subscription on the base key on <base>/**, other keys dropped in process
publisher routes it to <base>/_buf/<gid>, which nobody reads <base>/_buf_cpu
the subscriber receives nothing every message
message with no byte field, such as Float64MultiArray unchanged unchanged: stays out under Auto
transient-local subscriber unchanged unchanged: stays out, even under Cpu
key format other than rmw_zenoh's unchanged unchanged: stays out, even under Cpu
with_buffer_group(BufferGroup::Off) not available stays out

Behaviour

Evidence on main

The runs use the released ros-lyrical-rmw-zenoh-cpp 0.10.6 with three runs in each cell. The older releases are ros-humble-rmw-zenoh-cpp 0.1.11, ros-kilted-rmw-zenoh-cpp 0.6.8 and ros-jazzy-rmw-zenoh-cpp 0.2.11, with one run in each cell. The publisher is ros2 topic pub -r 5 with CPU buffers, so complete delivery in a 10 s window is 50 or 51. One process holds a typed subscriber on the topic. The probe was built from hiroz main before the fix. The Humble probe uses the humble feature. The Kilted and Jazzy probes use the default feature set, which is the Jazzy one. The probes count messages and do not compare payload contents.

Lyrical 0.10.6, three runs per cell, messages received on main:

Publisher message main
UInt8MultiArray 0, 0, 0
PointCloud2 0, 0, 0
visualization_msgs/Marker, which nests MeshFile 0, 0, 0
Float64MultiArray (control, no buffer field) 51, 50, 51

The 0 cells have two controls. In the same cell, a native ros2 topic hz subscriber read 5.000 Hz, so the publisher was producing. The same probe binary received 50 to 51 messages on Float64MultiArray, so the probe and the router work.

Older releases, one run per cell, typed subscriber, messages received on main:

Release Publisher message main
Humble 0.1.11 PointCloud2 50
Humble 0.1.11 String 50
Kilted 0.6.8 PointCloud2 50
Kilted 0.6.8 String 50
Jazzy 0.2.11 PointCloud2 50
Jazzy 0.2.11 String 50

On these releases main already delivers every message, so they show no loss. The loss follows the rmw_zenoh release and the message definition.

The rule that decides which messages carry buffers follows the message definition. In Lyrical an unbounded uint8[] is a rosidl::Buffer, directly or in a nested message. The reference is the compiled typesupport of one Lyrical install: its has_buffer_fields function, called for every message of the 223 packages that ship .msg files.

Rule Messages compared Mismatches
the exact rule: unbounded uint8[] or char[], directly or nested 2227 0
the same rule without nested messages (control) 2227 45
a fixed list of five messages (baseline) 2227 113, all missed buffer messages

118 of the 2227 messages have buffer fields. They include visualization_msgs/Marker, MarkerArray, the four interactive-marker messages, stereo_msgs/DisparityImage, map_msgs/PointCloud2Update and nav2_msgs/Costmap.

The comparison covers the exact rule, not the hiroz code. Hiroz applies the rule to the message schema, and a schema cannot tell byte from uint8. Hiroz therefore also counts an unbounded byte[]. In the bundled Jazzy .msg files, five messages count by the schema rule and not by the exact rule: std_msgs/ByteMultiArray, example_interfaces/ByteMultiArray, rcl_interfaces/ParameterValue, rcl_interfaces/Parameter and rcl_interfaces/ParameterEvent. A subscriber on one of them joins without need, and receives each message once.

Activity

  1. changed the title [-]Typed and dynamic subscribers receive nothing from buffer-aware rmw_zenoh publishers[/-] [+]hiroz typed and dynamic subscribers receive nothing from buffer-aware rmw_zenoh publishers[/+] on Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions