The sender needs the exact MAC address of the receiver, and both boards must use the same Wi-Fi channel.
What the message means
ESP-NOW sends frames straight to a peer by MAC address. A wrong address or a different channel means nothing arrives.
Fix it in this order
- Print WiFi.macAddress() on the receiver and copy it exactly into the sender.
- Set both boards to station mode before esp_now_init.
- Use the same channel on both. If one also joins a router, it uses the router channel.
- Register the peer with esp_now_add_peer before sending.
- Read the send callback status to see if delivery worked.
- Keep the data size within the limit of the protocol.
Why it happens
ESP-NOW only works when both boards are on the same Wi-Fi channel and the sender uses the right receiver MAC address. Putting the boards in station mode is also needed. The callback function signatures changed between versions of the ESP32 core.
Print the receiver MAC with WiFi.macAddress(), copy it into the sender, set WiFi.mode(WIFI_STA) on both, and use the callback signature that matches your core.
If you see this, do this
| You see | Do this |
|---|---|
| Callback says fail | Wrong MAC or channel. |
| Works until Wi-Fi connects | Channel changed by the router. |
Related
Wi-Fi will not connect, MQTT on the ESP32.
Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.
Why this happens
ESP-NOW sends a frame straight from one radio to another without joining a network. The sender needs the receiver’s MAC address, the frame travels on the current Wi-Fi channel, and the receiver must be listening on that channel. A single wrong byte in the address or a channel mismatch means the frame is never accepted.
A board that connects to a router moves to the router’s channel, which can differ from the other board. The Wi-Fi mode matters too: ESP-NOW works with the station interface, and the station MAC and the access-point MAC differ. Also, newer versions of the ESP32 Arduino core changed the callback function signatures, so an example written for an older core may not compile.
How to confirm the cause
- Print WiFi.macAddress() on the receiver after WiFi.mode(WIFI_STA), and compare it with the bytes in the sender, character by character.
- Print WiFi.channel() on both boards after the Wi-Fi mode is set.
- Check the return value of esp_now_add_peer and esp_now_send.
- Check the send callback status; a failure means that no acknowledgement arrived.
- Keep the payload to 250 bytes or less.
Worked example
Replace the MAC bytes with the value printed by your receiver. The message is only queued here, so also check the send callback in your own sketch.
#include <WiFi.h>
#include <esp_now.h>
uint8_t peerMac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC}; // placeholder: use your receiver's MAC
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) { Serial.println("init failed"); return; }
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, peerMac, 6);
peer.channel = 0; // 0 = current channel
peer.encrypt = false;
Serial.println(esp_now_add_peer(&peer) == ESP_OK ? "peer ok" : "peer failed");
const char msg[] = "hello";
Serial.println(esp_now_send(peerMac, (const uint8_t *)msg, sizeof(msg)) == ESP_OK ? "queued" : "error");
}
void loop() {}Common mistakes
- Using the MAC of the wrong board, or the soft-AP MAC instead of the station one.
- Leaving out WiFi.mode(WIFI_STA) before esp_now_init.
- Sending before the peer is added.
- Mixing callback signatures from different core versions.
If this did not fix it
- Check the distance and antenna orientation; test with the boards close together.
- Check the power supply, since Wi-Fi bursts can cause brown-outs.
- Check the encryption setting; both sides must agree if it is used.
- Check that one board is not connecting to a router and changing channel.