← All posts
EmbeddedPublished · 9 min readAlso on dev.to

Fix ESP32 Upload Errors: 'Failed to connect' and 'Wrong boot mode'

Uploading to an ESP32 often ends with a row of dots after Connecting... and then A fatal error occurred. There are only a handful of these messages, and each one tells you which stage of the upload stopped. This guide uses the exact wording from the esptool source code and walks through what to check for each message, in order.

Free tool featured in this guide
CNTerminal — free portable serial terminal

Handy for pressing EN and reading the boot line (boot:0x13 / boot:0x3), and its DTR toggle opens the port without an extra reset. Disconnect the port while you upload so esptool can use it.

Free download

An upload has four stages — find where it stopped

Arduino IDE, PlatformIO and ESP-IDF all upload through esptool. esptool opens the port, uses the DTR and RTS lines to reset the chip into download mode, syncs with the chip, and only then writes to flash. The error message tells you which of those stages failed, which cuts down what you need to check before you touch any code.

Port won't open: stage 1. Chip boots normally: stage 2. Chip never answers: stage 3. Data corrupted mid-transfer: stage 4.
MessageStageCheck first
Could not open COM3, the port is busy or doesn't exist.1. Open portOther programs using the port, port name, driver
Wrong boot mode detected (0x13)! The chip needs to be in download mode.2. Download modeBOOT button, parts wired to GPIO0/GPIO2
No serial data received.3. No answerManual download mode, cable, power
Download mode successfully detected, but getting no sync reply: The serial TX path seems to be down.3. SyncPC→ESP32 wiring (TX→RX)
Invalid head of packet (0x…): Possible serial noise or corruption.4. TransferLower upload speed, cable, hub
💡

Messages start with A fatal error occurred:, and connection-stage errors add Failed to connect to ESP32:. The chip name changes with the board, e.g. ESP32-S3 or ESP32-C3.

Could not open COM3 — the port won't open

text
A fatal error occurred: Could not open COM3, the port is busy or doesn't exist.
(could not open port 'COM3': PermissionError(13, 'Access is denied.', None, 5))

Hint: Check if the port is not used by another task

The part in parentheses is the real cause. PermissionError(13, …) means another program has the port open; FileNotFoundError(2, …) means there is no port with that name. An upload and a serial session can't share a port.

  • Close anything holding the port: PuTTY, a serial terminal, a serial monitor in another IDE window.
  • Keep Device Manager → Ports (COM & LPT) open and unplug the board. The entry that disappears is your port.
  • If nothing shows up at all, install the USB chip driver: CP2102/CP210x drivers come from Silicon Labs, CH340 drivers from WCH.
  • Charge-only USB cables power the board but never create a port. Swap to a cable with data lines.
ℹ️

esptool adds the Hint line by looking for the English text Access is denied. On a non-English Windows the error text is localized, so the busy-port hint may not appear. On Linux, Permission denied means your user needs to be in the dialout (or uucp) group.

No serial data received — the chip says nothing

text
Connecting........

A fatal error occurred: Failed to connect to ESP32: No serial data received.
For troubleshooting steps visit: https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html

The port opened, but after esptool reset the chip not a single byte came back. The PC-to-USB-chip side is fine, so look at the link between the USB chip and the ESP32, or at the chip itself. Work through these in order.

  1. 1Manual download mode: start the upload and hold BOOT while Connecting... is shown. If that isn't enough, keep holding BOOT and tap EN once. Once Writing at 0x… appears you can let go.
  2. 2Plug straight into a port on the back of the PC instead of a hub or front panel, with a short data cable.
  3. 3Power: the esptool docs say the ESP32's 3.3 V supply must handle peaks of 200–300 mA. Disconnect current-hungry parts such as motors or LED strips and try again.
  4. 4If you wired a bare module to a USB-serial adapter rather than using a dev board, check that adapter TX goes to ESP32 RX and adapter RX to ESP32 TX, with a common ground.
  5. 5Lower the upload speed to 115200 (see the transfer errors section below).

Wrong boot mode detected (0x13) — download mode was not entered

text
A fatal error occurred: Failed to connect to ESP32: Wrong boot mode detected (0x13)! The chip needs to be in download mode.

This one is half good news. esptool read the chip's boot log, so the serial link works. The chip just booted into the program in flash instead of download mode. esptool decides by checking whether the boot log that arrives right after reset contains waiting for download.

If GPIO0 is HIGH at the moment of reset the chip runs the app in flash; if it is LOW it enters download mode. The BOOT button pulls GPIO0 LOW.
  • Quickest fix: hold BOOT while Connecting... is shown (manual download mode, above).
  • Disconnect buttons, LEDs or sensors on GPIO0 and GPIO2. Holding GPIO0 HIGH externally blocks download mode, and GPIO2 must be floating or LOW to enter it.
  • Driving GPIO12 HIGH selects 1.8 V flash voltage, which breaks boards with 3.3 V flash. Check for a pull-up on that pin.
  • If you have to press BOOT every single time, the board's auto-reset circuit or a USB hub is the likely cause. Compare with another cable and USB port.
💡

The value in parentheses varies by chip; what matters is The chip needs to be in download mode. To see it yourself, open a serial monitor at 115200 and press EN. boot:0x13 (SPI_FAST_FLASH_BOOT) is a normal boot; boot:0x3 (DOWNLOAD_BOOT…) followed by waiting for download is download mode.

No sync reply — the PC-to-ESP32 line is down

text
A fatal error occurred: Failed to connect to ESP32: Download mode successfully detected, but getting no sync reply: The serial TX path seems to be down.

The chip entered download mode, but never answered esptool's sync messages. Its boot log reached the PC, so only the PC-to-ESP32 direction is broken. The esptool docs describe this message as a problem on the TX path from the host to the chip.

  • With a USB-serial adapter, check adapter TX → ESP32 RX (GPIO3, U0RXD on the ESP32) and the jumper contact.
  • On a dev board this is rare. Try another board with the same cable and PC to see whether the board itself is at fault.

Errors during transfer — Invalid head of packet, Serial data stream stopped

text
A fatal error occurred: Invalid head of packet (0x…): Possible serial noise or corruption.
A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.

The upload starts and the percentage climbs, then it dies. The esptool docs list poor USB cables, pins shorting on a breadboard, and the chip browning out as the usual causes. The common fix is a lower upload speed: uploads take longer but tolerate noise much better.

ToolWhere to set upload speed
Arduino IDETools → Upload Speed → 115200
PlatformIOupload_speed = 115200 in platformio.ini
ESP-IDFidf.py -p COM3 -b 115200 flash
esptool directly-b 115200 (the docs suggest going as low as -b 9600 to diagnose)
  • Use a short data cable plugged straight into the PC, not a hub.
  • On a breadboard, keep other wires and parts away from the flash pins (GPIO6–11 on the ESP32).
  • Disconnect high-current parts during the upload, or give them their own supply.

Quick checklist

  1. 1Could not open → close programs using the port; check port name, driver and cable.
  2. 2Wrong boot mode → hold BOOT during Connecting...; check parts on GPIO0, GPIO2, GPIO12.
  3. 3No serial data received → manual download mode; cable, USB port, power.
  4. 4no sync reply → PC-to-ESP32 wiring (TX→RX).
  5. 5Invalid head of packet mid-upload → speed 115200; cable, hub, power.
ℹ️

If the upload finishes but nothing runs, press EN once. The separate post 'Why your ESP32 resets every time you open the serial monitor' on this blog covers the opposite problem.

FAQ

Q. I have to press BOOT for every upload. Is the board broken?

No. Automatic uploads use the USB chip's DTR and RTS lines to sequence GPIO0 and EN, and depending on the board circuit or a USB hub that timing can miss. Compare with another cable, USB port and PC; if it's the same everywhere, treat it as a quirk of that board and keep using BOOT.

Q. The upload succeeds but the program doesn't run.

The chip is often still sitting in download mode. Press EN once. If you uploaded through the built-in USB on an ESP32-S3 or C3, its reset doesn't re-sample the strapping pins, which can cause this; esptool's --after watchdog-reset fixes it too.

Q. My ESP32-S3 board has two USB ports. Which one do I upload through?

Usually one goes through a USB-serial chip (labelled UART or COM) and the other is the chip's built-in USB. Both can upload, but if your program reconfigures or disables the built-in USB pins, that port disappears from the PC. Hold BOOT and press EN to enter download mode and it comes back.

Q. The COM port number keeps changing.

Windows can assign a new COM number depending on the USB chip and which USB port you plug into. The same board in the same USB port usually keeps its number, so check Device Manager by unplugging and replugging the board.

Q. I can't find the Upload Speed menu in Arduino IDE.

Tools → Upload Speed appears once an ESP32 board is selected. Check that Tools → Board is set to your board, for example ESP32 Dev Module.

Free tool featured in this guide
CNTerminal — free portable serial terminal

Handy for pressing EN and reading the boot line (boot:0x13 / boot:0x3), and its DTR toggle opens the port without an extra reset. Disconnect the port while you upload so esptool can use it.

Free download

More posts