{"record":{"id":"2f92f5c4c1c1b5dd","repo":"ruvnet/RuView","slug":"mqtt-publish-failed-topic-topic-rc-info-rc","errorCode":null,"errorMessage":"mqtt publish failed: topic={topic} rc={info.rc}","messagePattern":"mqtt publish failed: topic=(.+?) rc=(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/wifi_densepose/client/mqtt.py","lineNumber":177,"sourceCode":"        self,\n        topic: str,\n        payload: Any,\n        *,\n        qos: int = 0,\n        retain: bool = False,\n    ) -> None:\n        \"\"\"Publish a payload. Dicts/lists are JSON-encoded; bytes pass\n        through; strings are encoded UTF-8.\"\"\"\n        if isinstance(payload, (dict, list)):\n            data: Any = json.dumps(payload, default=str)\n        else:\n            data = payload\n        info = self._client.publish(topic, data, qos=qos, retain=retain)\n        # paho v2 returns MQTTMessageInfo; rc != MQTT_ERR_SUCCESS is a\n        # broker-side error we should propagate so callers don't think\n        # the publish succeeded.\n        if info.rc != mqtt.MQTT_ERR_SUCCESS:\n            raise RuntimeError(f\"mqtt publish failed: topic={topic} rc={info.rc}\")\n\n    # ── paho callbacks (v2 signatures) ───────────────────────────────\n\n    def _on_connect(self, client: Any, _userdata: Any, _flags: Any, reason_code: Any, _properties: Any = None) -> None:\n        # paho v2 passes ReasonCode; success is 0 (\"Success\" / Granted_QoS_0)\n        rc = int(reason_code) if hasattr(reason_code, \"__int__\") else reason_code\n        if rc == 0:\n            self._connected_event.set()\n            # Re-subscribe to all known patterns. Important after a\n            # reconnect — paho doesn't auto-resubscribe with\n            # clean_session=True.\n            with self._handlers_lock:\n                patterns = list(self._handlers.keys())\n            for pattern in patterns:\n                client.subscribe(pattern)\n            log.debug(\"mqtt CONNACK ok; subscribed to %d pattern(s)\", len(patterns))\n        else:\n            log.warning(\"mqtt CONNACK with non-success rc=%r\", reason_code)","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/python/wifi_densepose/client/mqtt.py#L159-L195","documentation":"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.","triggerScenarios":"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.","commonSituations":"Broker restarts or network flaps; a request handler racing the MQTT connect; localhost broker not running inside a container.","solutions":["Gate publishes on connection: client.start() then client.wait_connected(timeout=5.0) (or check the `connected` property) before publishing","Verify the broker is reachable: correct broker_host/broker_port, firewall open, broker process running","Retry transient rc=4 (MQTT_ERR_NO_CONN) with backoff after reconnecting","If bursts overflow the QoS queue, throttle publishers or lower QoS"],"exampleFix":"# before\nclient = RuViewMqttClient(broker_host=\"localhost\")\nclient.start()\nclient.publish(\"ruview/node1/raw/edge_vitals\", {...})  # rc=4: not connected yet\n\n# after\nclient = RuViewMqttClient(broker_host=\"localhost\")\nclient.start()\nif not client.wait_connected(timeout=5.0):\n    raise RuntimeError(\"broker did not send CONNACK within 5s\")\nclient.publish(\"ruview/node1/raw/edge_vitals\", {...})","handlingStrategy":"retry","validationCode":"client.start()\nif not client.wait_connected(timeout=5.0):\n    raise RuntimeError(\"MQTT broker unreachable; check broker_host/broker_port\")\n# client.connected is now True; safe to publish","typeGuard":null,"tryCatchPattern":"import time\n\ndef robust_publish(client, topic, payload, attempts=3):\n    for i in range(attempts):\n        if not client.connected:\n            client.start()\n            client.wait_connected(timeout=5.0)\n        try:\n            client.publish(topic, payload)\n            return\n        except RuntimeError as e:\n            if i == attempts - 1:\n                raise\n            time.sleep(2 ** i)  # backoff, reconnect, retry","preventionTips":["Always gate publishes on wait_connected() or the connected property","Buffer telemetry during outages and drain after reconnect instead of publishing blind","Monitor broker health so reconnects happen before the publish path needs them"],"tags":["mqtt","network","publish","runtime","paho","connection"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}