Skip to content

v5.3.0 transport detection has no fallback when the port cannot be enumerated (virtualised serial devices) — stub upload then fails (ESPTOOL-1370) #1181

Description

@keithshawlab

Operating System

Container: Ubuntu 24.04 (Docker, espressif/idf:v6.0.2). Host: macOS 15 (Apple Silicon), OrbStack 2.2.3.

Esptool Version

v5.3.0 and v5.3.1 fail. v5.2.0 and v4.8.1 succeed.

Python Version

3.12 (IDF's bundled venv, pyserial from the same env)

Chip Description

ESP32-S3 (QFN56, revision v0.2), 16MB flash, 8MB embedded PSRAM (AP_3v3), native USB (USB-OTG, 303a:0009)

Device Description

LilyGo T-Display S3. No USB-serial bridge chip — USB-C goes directly to the ESP32-S3's USB peripheral.

Hardware Configuration

Nothing attached that touches the USB or strapping pins.

How is Esptool Run

From inside a Docker container. The host's serial device is exposed to the container by OrbStack, which forwards it under its macOS name (/dev/cu.usbmodem2101) as a character device with no sysfs USB backing and no ttyACM* equivalent.

Full Esptool Command Line that Was Run

esptool --chip esp32s3 --port /dev/cu.usbmodem2101 flash-id

Esptool Output

esptool v5.3.0
Serial port /dev/cu.usbmodem2101:
Connecting...
Failed to get VID/PID of a device on /dev/cu.usbmodem2101, using standard reset sequence.
Connected to ESP32-S3 on /dev/cu.usbmodem2101:
Chip type:          ESP32-S3 (QFN56) (revision v0.2)
Features:           Wi-Fi, BT 5 (LE), Dual Core + LP Core, 240MHz, Embedded PSRAM 8MB (AP_3v3)
Crystal frequency:  40MHz
MAC:                e0:72:a1:a2:d1:e4
Uploading stub flasher...

A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.

More Information

Summary: v5.3.0's "Add transport mode detection based on USB VID:PID instead of hard-coded ROM symbols" has no fallback when the port cannot be enumerated. _get_vid_pid() matches serial.tools.list_ports.comports() entries by device path; where the OS exposes a serial device without USB descriptors, that list is empty, so the lookup returns (None, None) and esptool silently treats a native-USB part as a UART bridge. The stub upload is the first operation that fails.

This is not specific to OrbStack — it should reproduce anywhere a serial port is presented without USB descriptors (VM passthrough, socat/RFC2217-style bridges, some WSL setups, udev symlink arrangements).

Enumeration, same board, same moment:

container:  comports found: 0
macOS host: comports found: 3
            /dev/cu.usbmodem2101  vid=0x303a pid=0x0009  ESP32-S3

Controlled matrix — same board, same silicon revision, same cable:

esptool Transport detection Where Stub upload
4.8.1 none (ROM symbols) container works
5.2.0 none (ROM symbols) container works
5.3.0 succeedsUSB mode: USB-OTG host, real USB works
5.3.0 fails → standard reset sequence container fails
5.3.1 fails → standard reset sequence container fails

The third row is the positive control: the same 5.3.0 with the same esp-flasher-stub succeeds on this exact board as soon as VID/PID resolves. So the stub binary is not incompatible with this chip — the detection is what breaks it. 5.2.0 has no transport concept to get wrong, which is why it is unaffected despite also having no VID/PID.

Workarounds: --no-stub works (≈23 s vs ≈13 s for a 1.2 MB image, since the ROM loader cannot do compressed writes). Pinning esptool==5.2.0 restores full behaviour including idf.py flash.

--before usb-reset does not help — possibly a second bug. It is OR'd into the reset choice (loader.py:815), but the device-type predicates at loader.py:1242 / 1248 call get_usb_vid_pid() directly, so an explicit flag cannot override a failed lookup:

$ esptool --chip esp32s3 --port /dev/cu.usbmodem2101 --before usb-reset flash-id
Failed to get VID/PID of a device on /dev/cu.usbmodem2101, using standard reset sequence.
Uploading stub flasher...
A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.

Suggested fix: an explicit override for when enumeration is impossible — e.g. --usb-mode {auto,usb-otg,usb-jtag-serial,uart}, or honouring --before usb-reset in the device-type predicates. Descriptors the hypervisor does not pass through cannot be recovered by probing, so detection alone can never cover this case. Falling back to 5.2.0's ROM-symbol detection when the lookup fails would also work.

Not a duplicate of #1178 / esp-flasher-stub#94. Those share the symptom (ESP32-S3 rev v0.2, failure at Uploading stub flasher..., 5.3.0 vs 4.8.1) but were intermittent — a second identical board never failed, the original recovered days later unchanged, and the report was closed as not reproducible. This failure is 100% deterministic and tracks the environment exactly: it fails whenever comports() is empty and succeeds whenever it is not.

I Have Read the Troubleshooting Guide

Yes. The applicable remedies were tested and none change the outcome:

Remedy Result
Lower baud rate (--baud 9600) No change — identical failure
timeout = 60, mem_end_rom_timeout = 20 via esptool.cfg No change (Loaded custom configuration confirmed)
--chip esp32s3 to skip autodetection Already always specified
Cable / hub / shorter path Same cable succeeds with 5.2.0, and with 5.3.0 on the host
Power, brownout Same board and supply; outcome depends only on esptool version
SPI pins disconnected Devkit, nothing attached to SPI or strapping pins
USB-to-Serial drivers N/A — no bridge chip, native USB-OTG
Port permissions / in use Port opens; chip ID, MAC and flash-id reads all succeed

The version bisect on identical hardware is what rules out the serial-quality class of causes:
the failure tracks the esptool version and the enumeration environment, nothing physical.

Other Steps to Reproduce

Reproduces on any serial device presented without USB descriptors, not just OrbStack — VM
passthrough, socat/RFC2217 bridges, some WSL setups. The precondition is testable without
hardware:

python -c "import serial.tools.list_ports as l; print(len(list(l.comports())))"   # 0 => affected

I Have Read the Troubleshooting Guide

  • I confirm I have read the troubleshooting guide.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions