Downlink data does not pass from Mosquitto to ChirpStack

Hi all,

Downlink data does not pass from Mosquitto to ChirpStack. Uplink data is reaching from LoRa terminal to Node-RED. The situation is as follows. Could you please give me some kind and friendly advice?

The downlink data path is as follows.
Node-RED → MQTT broker (Mosquitto) → ChirpStack LoRaWAN Network Server → LoRa Gateway (Packet Forwarder) → LoRa terminal

To send “02” data from a Node-RED node to Port=6 of a LoRa terminal.

Node-RED node encoded the payload data into Base64 and published it from the “MQTT out” node to Mosquitto.

When I subscribe to the topic at the MQTT broker (Mosquitto), I get the following result: Data has been received from Node-RED to Mosquitto.

application/d77f05e9-c36f-458a-bf91-4cfdafc9c4cc/device/aa00cc01ee020040/command/down {“devaddr”: “00169871”, “data”: “MDI=”", “port”:6}

The data from the ChirpStack LoRaWAN Network Server to the LoRa terminal was sent to Port=6 in Queue of ChirpStack with “02” data as HEX data, and it was confirmed that the LoRa terminal was working properly.

However, the data sent from Node-RED did not reach the LoRa terminal.

The Network Server’s events shows “Code: DOWNLINK_GATEWAY Level: ERROR,” indicating that sending data from Mosquitto to the ChirpStack LoRaWAN Network Server was an error.

Could you please tell me the cause of the error from Mosquitto to ChirpStack and the countermeasure?

Best Regards,
Hiroshi Mori

Scheduling downlinks via MQTT is supported and has been for a long time:

I usually do so via gRPC, but it might be convenient if you’re doing a lot of downlinks with decoded objects, I suppose.

1 Like

Ah my bad, thanks for the clarification. Does Chirpstack then “translate” the message into the “<region_prefix>/gateway/<gateway_id>/command/down” topic format which the Gateway Bridge subscribes to?

As for the original post could it be that the payload is incorrect? From the link @bconway posted it appears your MQTT payload:

{“devaddr”: “00169871”, “data”: “MDI=”", “port”:6}

is missing important information like devEui and Confirmed.

I decided to play around with MQTT downlinks myself a bit today, I hadn’t known it was a Chirpstack feature until bconway enlightened me. Just for testing I used your message in the following command:

mosquitto_pub -h <mosquitto-ip> -t application/<my-app-id>/device/<my-dev-eui>/command/down -m '{"devaddr": "00169871", "data": "MDI=", "port":6}' -q 1

And got the this warning in my docker logs (I am running CS V4 using docker)

chirpstack-1     | 2024-03-20T17:57:24.158145Z  WARN chirpstack::integration::mqtt: 
Processing command error: Payload dev_eui  does not match topic dev_eui 0080000004078e55 

A different issue than what you got but an issue nonetheless. After changing the message to include the necessary values in the post bconway made the command is as follows:

mosquitto_pub -h <mosquitto_ip> -t application/<my-app-id>/device/<my-dev-eui>/command/down -m '{"devEui": "<my-dev-eui>", "confirmed": true, "fPort": 10, "devaddr": "00169871", "data": "MDI=", "port":6}' -q 1

Using this command the message was sent successfully and received by my device. Maybe these missing values are your issue.

And to answer my own question from the previous post, Chirpstack subscribes to


When it recieves a message there it adds the downlink to the device’s queue, so then the next time the device uplinks Chirpstack publishes the message on the topic:


Which the gateway-bridge/mqtt forwarder subscribes to and translates the message to the gateway.

Hi Liam_Philipp,

Sorry for the very late reply. Thank you for your detailed advice and verification results.
I tried the above OK description. I got the following result “Error: Connection refused”.

The current configuration is that the connection between Mosquitto and ChirpStack is not in TSL configuration.
Is this the cause?

$ mosquitto_pub -h -t application/d77f05e9-c36f-458a-bf91-4cfdafc9c4cc/device/aa00cc01ee020040/command/down -m '{"devEui": "aa00cc01ee020040", "confirmed": true, "fPort": 10, "devaddr": "01d3d76b", "data": "Ag==", "port":6}' -q 1
Error: Connection refused

Best Regards,
Hiroshi Mori

Connection refused means it’s not listening on the port (or IP) you expect and/or you can’t reach it.

1 Like

I think you are missing the port, add -p 1883 in your call and it should work (assuming you have the correct IP). Not sure how I got away without that on my call, maybe I forgot to copy paste that part of the command.

Thanks for your great advice. I was able to downlink. I made a mistake in setting the IP address; it should have been “localhost” since ChirpStack and mosquitto are installed on the same Linux machine.

I will consider writing JavaScript for the function node of the Node-RED downlink packet with reference to the mosquitto command you taught me.

By the way, could you please tell me more?

Question 1
What does “fPort” in the mosquitto command mean?
What is it set to?

Question 2
I get a lot of the following errors and Warnings. Nearly 50% of the log is Warning. What is wrong?
The ChirpStack log is as follows.




description:"Uplink was flagged as re-transmission / frame-counter did not increment"

Best Regards,
Hiroshi Mori

Question 1:

Cstratton describes fport usage well in this forum post: What is fport used for when rx and tx

Question 2:


With every message a device should increment the fcount value it sends along with the message by 1. This is used to prevent replay attacks, so Chirpstack discards any message that has an fcount smaller than or equal to the last fcount it received from that device, assuming it to be an attacker retransmitting a message (such as a join request to attempt to have the server send the attacker new session keys so it can impersonate the device).

As for this error it means your device is sending fcount that are equal or less than the previous uplinks fcount.

What device are you using? If it is something “homebrew” that doesn’t increment fcounts you can disable the fcount verification in the “configuration” tab of the devices page.

If the device does increment fcount (as all retail LoRaWAN devices should) then you could try disabling the fcount verification, let the device uplink once so Chirpstack recognizes the current fcount, and then enable it again. Essentially letting Chirpstack sync fcounts with the device again.

If neither of these are the case then it is likely something wrong with the device, as Chirpstack is just doing its job preventing attackers.

Downlink Gateway Too Early:

This is a common error when using the UDP packet forwarder on a gateway. Brocaar explains it well in this forum post: Lora Server to GW MQTT ACK: "TOO EARLY" - #3 by brocaar

Although if it only happens rarely it can be ignored with little issue.

Hi Liam_Phillipp,

Thank you very much for your very detailed advice.

Regarding question 1
I understood.
For ChirpStack, I see that “FPort” in MACPayload needs to be mentioned in the Payload data as well.

Regarding question 2、
I have uploaded Confirmed data, so if the ACK is not returned, “Code: UPLINK_F_CNT_RETRANSMISSION Level: WARNING” appeared to send again with the same FCnt.

I was able to counteract this by disabling fcount verification in the “configuration” tab of the device page.

However, “Code: DOWNLINK_GATEWAY Level: ERROR” is occurring about 10% of the time.

As you advised, I would like to change the setting in Chirpstack.toml to change the timing of the Gateway downlink.

However, I cannot find where to make the adjustment.

What part of the following file should I modify?

$ sudo cat /etc/chirpstack/chirpstack.toml
# Logging.

  # Log level.
  # Options are: trace, debug, info, warn error.

# PostgreSQL configuration.

  # PostgreSQL DSN.
  # Format example: postgres://<USERNAME>:<PASSWORD>@<HOSTNAME>/<DATABASE>?sslmode=<SSLMODE>.
  # SSL mode options:
  #  * disable - no SSL
  #  * require - Always SSL (skip verification)
  #  * verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA)
  #  * verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate)

  # Max open connections.
  # This sets the max. number of open connections that are allowed in the
  # PostgreSQL connection pool.

  # Min idle connections.
  # This sets the min. number of idle connections in the PostgreSQL connection
  # pool (0 = equal to max_open_connections).

# Redis configuration.

  # Server address or addresses.
  # Set multiple addresses when connecting to a cluster.

  # Redis Cluster.
  # Set this to true when the provided URLs are pointing to a Redis Cluster
  # instance.

# Network related configuration.

  # Network identifier (NetID, 3 bytes) encoded as HEX (e.g. 010203).

  # Enabled regions.
  # Multiple regions can be enabled simultaneously. Each region must match
  # the 'name' parameter of the region configuration in '[[regions]]'.

# API interface configuration.

  # interface:port to bind the API interface to.

  # Secret.
  # This secret is used for generating login and API tokens, make sure this
  # is never exposed. Changing this secret will invalidate all login and API
  # tokens. The following command can be used to generate a random secret:
  #   openssl rand -base64 32



Best Regards,
Hiroshi Mori