Docs / When it doesn't work
It compiled. It flashed. The board still won't boot.
An ESP32-S3 that accepts a sketch and then loops on Invalid image block, can't boot is almost never a problem with your code. It is the board settings the image was built with.
What you're seeing
The upload succeeds. The serial monitor then prints the same block over and over, a few times a second:
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0x8 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40043ac8
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x10cc
load:0x3cc0c8ff,len:0x3cc11c40
Invalid image block, can't boot.
ets_main.c 329
Nothing in that block is produced by your sketch. Every line comes from the mask ROM bootloader, which runs before a single instruction of your code. That is the first and most useful thing it tells you.
The second load: line is the whole answer
Read the two load lines against each other:
| Line | Address | Length | Verdict |
|---|---|---|---|
| first segment | 0x3fce2820 | 0x10cc = 4,300 bytes | sane — valid internal SRAM, a believable size |
| second segment | 0x3cc0c8ff | 0x3cc11c40 = 1,019,288,640 bytes | impossible |
The second length is roughly 972 MB. The chip has 512 KB of internal SRAM and at most 32 MB of flash. The address is also unaligned — it ends in ff, and segment addresses are four-byte aligned.
Look closer and the shape gives the mechanism away: 0x3cc0c8ff and 0x3cc11c40 are both values in the 0x3Cxx_xxxx range. The loader is reading an address where a length should be. It is not parsing a slightly wrong image — it has lost its place in the header entirely, so everything after that point is noise.
rst:0x7 (TG0WDT_SYS_RST) on the first line is the watchdog resetting a boot that never completed. That is the loop, not the cause. And boot:0x8 (SPI_FAST_FLASH_BOOT) confirms the board is trying a normal flash boot, so it is not stuck in download mode and the strapping pins are fine.
Why "it flashed successfully" proves nothing here
Which is why the two facts in the same sentence — "it flashed perfectly" and "invalid image block" — are not a contradiction. They are measurements of two different things.
Fixing it
The settings that matter are the ones baked into the image header, in this order:
- Flash size. If the build says 4 MB and the module has 16 MB, the partition table lands where the ROM is not looking. This alone produces exactly the log above.
- PSRAM type. An
R8module has octal PSRAM and needs the OPI setting. Built as QSPI or disabled, it will not come up. - Flash mode. QIO / DIO / OPI must match the part. A mode mismatch is the classic cause of reads that come back shifted.
- Flash frequency. Some modules — clones especially — are not reliable at 80 MHz. 40 MHz is the safe test.
Then erase the whole chip and reflash. If only the sketch was rewritten, a bootloader or partition table left over from a differently-configured build will disagree with the new image, and the symptom survives every subsequent upload. In the Arduino IDE that is Erase All Flash Before Sketch Upload; with esptool it is erase_flash.
The variant trap: N16R8 is not "an ESP32-S3"
The suffix on the module is not decoration. On an ESP32-S3-DevKitC-1 N16R8, N16 is 16 MB of flash and R8 is 8 MB of octal PSRAM. An S3 SuperMini is a different part with different memory. Selecting a generic "ESP32S3 Dev Module" and leaving the defaults gives you 4 MB flash and no PSRAM — wrong on both counts for an N16R8.
N16R8, N8R2, N8 and the rest each need different settings, and the boot log cannot tell you which board you have. One look at the module answers it.
Letting Soldr do it
Flashing straight from the browser sidesteps the whole category, because the target is chosen from the board in your build rather than from a menu you set by hand. If you have already taken the code into your own IDE, paste the boot log into Soldr and it will read the segment lines with you.
If it still won't boot
Work down, stopping when the second load: line becomes believable:
- Change only the flash size to match the module, erase, reflash. If the log changes, that was it.
- Then PSRAM: OPI for an
R8, disabled for a module with none. - Then flash mode, then drop the frequency to 40 MHz.
- If none of that moves the second
load:line, flash a known-good prebuilt binary for the same board. If that also fails, the module itself is suspect — counterfeit flash is common at the bottom of the market.
The test throughout is that one line. A board that is going to boot prints a second segment with a plausible address and a length in the tens or hundreds of kilobytes.