Back to blog
ROS2DDS

Your ROS2 Subscriber Is Not Receiving Messages. No Error. No Warning. Nothing.

Your publisher is running. `ros2 topic echo` shows data flowing out. Your subscriber node is alive. The callback never fires. No error in the log. No warning on the console. Nothing. This is a QoS mis

Blai Morte

Blai Morte

Co-Founder

·5 min read

Your publisher is running. ros2 topic echo shows data flowing out. Your subscriber node is alive. The callback never fires. No error in the log. No warning on the console. Nothing. This is a QoS mismatch, and ROS2 chose not to tell you about it.

What QoS Actually Controls

QoS (Quality of Service) in ROS2 is not a suggestion. It is a contract between a publisher and a subscriber. The contract has seven dimensions: reliability, durability, history, depth, deadline, lifespan, and liveliness. A mismatch on any dimension means the connection is silently dropped.

The most common mismatch is reliability. A publisher using RELIABLE and a subscriber using BEST_EFFORT will not talk to each other. The topic exists. Both sides are running. The DDS layer discards the connection and moves on.

This is not a networking bug. This is a design decision in ROS2: the runtime knows both sides of the connection, knows they are incompatible, and reports nothing by default.

The Seven Dimensions That Can Break You

Reliability is the one most people hit first. But the others matter too.

DurabilityVOLATILE vs TRANSIENT_LOCAL. A VOLATILE publisher does not retain messages for subscribers that connect late. A TRANSIENT_LOCAL subscriber expects the last N messages on connect. If they do not match, the subscriber waits for data that will never arrive.

HistoryKEEP_LAST vs KEEP_ALL. KEEP_LAST with depth 10 keeps the 10 most recent messages. KEEP_ALL tries to keep everything. On a fast publisher with a slow subscriber, KEEP_ALL on both sides can cause memory growth and dropped messages without warning.

Depth — Works with KEEP_LAST. A depth of 1 means the subscriber only buffers the latest message. If your callback processing takes longer than the publishing interval, you lose intermediate messages silently.

Deadline — Both sides agree on a maximum interval between messages. Miss the deadline and the DDS layer may report a missed deadline event, but ROS2 does not surface this as a topic-level error by default.

Lifespan — A publisher can set an expiration time on messages. If the subscriber is not ready to receive before the lifespan expires, the message is dropped. Again, silently.

You do not need to understand all seven to write a working ROS2 system. You do need to understand them to debug one that stopped working for no visible reason.

How to Find a QoS Mismatch

The tool exists. Most people learn about it after spending an hour eliminating every other possibility.

bash
ros2 topic info /your_topic --verbose

This shows the QoS profile of every publisher and every subscriber on that topic. If reliability does not match, the connection is incompatible. The output does not flag this in red. It just lists the profiles side by side and leaves the inference to you.

bash
ros2 topic info /cmd_vel --verbose

Look for the Reliability line under Publishers and Subscribers. If one says RELIABLE and the other says BEST_EFFORT, that is your silent failure.

Fixing It in Code

When you create a publisher or subscriber, you can pass an explicit QoS profile. The defaults are RELIABLE for publishers and BEST_EFFORT for some subscribers, depending on the client library and the topic type. Do not assume they match.

python
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy

# Explicit profile for a control command
control_qos = QoSProfile(
    reliability=ReliabilityPolicy.RELIABLE,
    durability=DurabilityPolicy.VOLATILE,
    depth=10
)

self.cmd_pub = self.create_publisher(Twist, '/cmd_vel', control_qos)
python
# Matching subscriber
self.cmd_sub = self.create_subscription(
    Twist,
    '/cmd_vel',
    self.cmd_callback,
    control_qos  # must match the publisher
)

If the publisher and subscriber do not agree on reliability, the subscription will not connect. ros2 topic info will show both endpoints, but no data will flow.

A Common Case: Sensor Data on WiFi

The default RELIABLE setting on a wired local network works fine. On WiFi, especially at range or with interference, RELIABLE triggers constant retransmissions. DDS tries to guarantee delivery over a lossy medium, creates congestion, and your effective bandwidth collapses.

For sensor data — LIDAR scans, camera frames, IMU streams — switch to BEST_EFFORT:

python
sensor_qos = QoSProfile(
    reliability=ReliabilityPolicy.BEST_EFFORT,
    depth=10
)

self.scan_sub = self.create_subscription(
    LaserScan,
    '/scan',
    self.scan_callback,
    sensor_qos
)

Stale sensor frames are discarded anyway by downstream processing. The retransmission overhead of RELIABLE on WiFi buys you nothing and costs latency and throughput.

For control commands — /cmd_vel, service calls, lifecycle transitions — keep RELIABLE. Missing a control command matters. Missing a single scan frame at 10Hz does not.

The Design Decision Worth Questioning

This failure mode is not hard to detect. The runtime compares both QoS profiles at connection time. It could log a warning. It could reject the subscription with an explicit error. It does neither.

The result: hours of debugging that start with "is the node running?" and end with "the reliability policy was wrong." The fix takes two minutes. The diagnosis takes two hours because the system chose not to surface the mismatch.

What to Check Before You Assume a Network Bug

When a subscriber stops receiving data, check these three things before you touch your network configuration:

1. Is the topic actually publishing? ros2 topic hz /your_topic 2. Do the QoS profiles match? ros2 topic info /your_topic --verbose 3. Is the subscriber alive? ros2 node info /your_node_name

If the topic is publishing and the node is alive but no data arrives, the QoS mismatch is the most likely cause. It is also the last place most people look.

Continue reading

Related Posts