ruvnet/RuView · error · RuntimeError

mqtt publish failed: topic={topic} rc={info.rc}

Error message

mqtt publish failed: topic={topic} rc={info.rc}

What it means

RuViewMqttClient.publish raises RuntimeError when paho's publish() returns an MQTTMessageInfo with rc != MQTT_ERR_SUCCESS. Non-zero rc means the broker did not accept the message — most commonly MQTT_ERR_NO_CONN (4) because CONNACK has not arrived or the connection dropped. The wrapper propagates this so callers cannot mistake a failed publish for success.

Source

Thrown at python/wifi_densepose/client/mqtt.py:177

        self,
        topic: str,
        payload: Any,
        *,
        qos: int = 0,
        retain: bool = False,
    ) -> None:
        """Publish a payload. Dicts/lists are JSON-encoded; bytes pass
        through; strings are encoded UTF-8."""
        if isinstance(payload, (dict, list)):
            data: Any = json.dumps(payload, default=str)
        else:
            data = payload
        info = self._client.publish(topic, data, qos=qos, retain=retain)
        # paho v2 returns MQTTMessageInfo; rc != MQTT_ERR_SUCCESS is a
        # broker-side error we should propagate so callers don't think
        # the publish succeeded.
        if info.rc != mqtt.MQTT_ERR_SUCCESS:
            raise RuntimeError(f"mqtt publish failed: topic={topic} rc={info.rc}")

    # ── paho callbacks (v2 signatures) ───────────────────────────────

    def _on_connect(self, client: Any, _userdata: Any, _flags: Any, reason_code: Any, _properties: Any = None) -> None:
        # paho v2 passes ReasonCode; success is 0 ("Success" / Granted_QoS_0)
        rc = int(reason_code) if hasattr(reason_code, "__int__") else reason_code
        if rc == 0:
            self._connected_event.set()
            # Re-subscribe to all known patterns. Important after a
            # reconnect — paho doesn't auto-resubscribe with
            # clean_session=True.
            with self._handlers_lock:
                patterns = list(self._handlers.keys())
            for pattern in patterns:
                client.subscribe(pattern)
            log.debug("mqtt CONNACK ok; subscribed to %d pattern(s)", len(patterns))
        else:
            log.warning("mqtt CONNACK with non-success rc=%r", reason_code)

View on GitHub (pinned to 4685618388)

Solutions

  1. Gate publishes on connection: client.start() then client.wait_connected(timeout=5.0) (or check the `connected` property) before publishing
  2. Verify the broker is reachable: correct broker_host/broker_port, firewall open, broker process running
  3. Retry transient rc=4 (MQTT_ERR_NO_CONN) with backoff after reconnecting
  4. If bursts overflow the QoS queue, throttle publishers or lower QoS

Example fix

# before
client = RuViewMqttClient(broker_host="localhost")
client.start()
client.publish("ruview/node1/raw/edge_vitals", {...})  # rc=4: not connected yet

# after
client = RuViewMqttClient(broker_host="localhost")
client.start()
if not client.wait_connected(timeout=5.0):
    raise RuntimeError("broker did not send CONNACK within 5s")
client.publish("ruview/node1/raw/edge_vitals", {...})
Defensive patterns

Strategy: retry

Validate before calling

client.start()
if not client.wait_connected(timeout=5.0):
    raise RuntimeError("MQTT broker unreachable; check broker_host/broker_port")
# client.connected is now True; safe to publish

Try / catch

import time

def robust_publish(client, topic, payload, attempts=3):
    for i in range(attempts):
        if not client.connected:
            client.start()
            client.wait_connected(timeout=5.0)
        try:
            client.publish(topic, payload)
            return
        except RuntimeError as e:
            if i == attempts - 1:
                raise
            time.sleep(2 ** i)  # backoff, reconnect, retry

Prevention

When it happens

Trigger: Calling publish() immediately after start() (before the background loop receives CONNACK); publishing after a broker disconnect; publishing without ever calling start(); overflowing paho's in-flight QoS queue.

Common situations: Broker restarts or network flaps; a request handler racing the MQTT connect; localhost broker not running inside a container.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/2f92f5c4c1c1b5dd. Report an issue: GitHub.