images/esp-idf/Dockerfile pins the harness at 2.8.1 (lines 59-63). The bug that made
those pins worth having in the first place is fixed upstream as of 2.9.0, so the pins
should move to 2.9.3.
Why now
_PopenRedirectProcess._forward_io read the redirect log in text mode while the file was
still being appended to, so a UTF-8 sequence straddling a read boundary raised
UnicodeDecodeError. Since 2.0.0 an except Exception swallowed it: the forwarder exited 0
with an empty stderr and DUT output stopped for the rest of the session, surfacing much later
as a pexpect timeout naming an unrelated test.
Fixed in espressif/pytest-embedded#426 (issue espressif/pytest-embedded#425), released in
v2.9.0 on 2026-08-25. Verified in the published wheel rather than from the changelog:
pytest_embedded/log.py in 2.8.1 has no open(logfile, 'rb'), 2.9.0 and 2.9.3 do.
Consumer context: jethome-iot/jetcontrol-cpp#462, where this cost about a day of misdiagnosis
and is currently held off by a source lint banning non-ASCII in device log calls. That lint
can be dropped once the images carry the fix.
The change
images/esp-idf/Dockerfile, lines 59-63 only:
pytest-embedded==2.9.3
pytest-embedded-serial==2.9.3
pytest-embedded-serial-esp==2.9.3
pytest-embedded-idf==2.9.3
pytest-embedded-qemu==2.9.3
Nothing else moves. Checked against PyPI metadata:
| Pin |
Now |
Latest |
Action |
esptool |
5.3.1 |
5.3.1 |
keep — pytest-embedded-serial-esp still requires esptool<6,>=5.2, unchanged between 2.8.1 and 2.9.3 |
pytest |
9.1.1 |
9.1.1 |
keep — requirement is still pytest>=7.0 |
pytest-timeout |
2.4.0 |
2.4.0 |
keep |
pytest-cov |
7.1.0 |
7.1.0 |
keep |
requires_python is >=3.10 in both releases, and the image runs 3.12.3.
Because esptool does not move, the assertion at line 102
(grep -qx 'esptool==5.3.1' /opt/esp/python-packages.txt) stays as it is.
Scope: one Dockerfile
The harness is pinned in images/esp-idf/Dockerfile and nowhere else.
images/esp-matter/Dockerfile has no harness pins — it is FROM the esp-idf image and picks
the new versions up on rebuild. Its line 140 reads ^esptool== out of the base's
/opt/esp/python-packages.txt; since esptool is unchanged, that check is unaffected.
images/platformio/Dockerfile is unrelated to the harness.
Verification after the bump
Bumping the number is not the same as getting the fix, so please confirm the behaviour rather
than the version string: build the image, then emit a non-ASCII character from a DUT in a
QEMU run — a single printf with an em dash (U+2014) in the device output is enough — and
check that the run completes instead of stopping mid-stream. On 2.8.1 that reproduces as a
pexpect.exceptions.TIMEOUT with nothing in the logs mentioning decoding.
The existing python -m pip check and the pip freeze snapshot in the verification layer
cover the rest.
Unrelated observation
While checking the pins: images/platformio/Dockerfile has PIO_VERSION=6.1.18 against 6.1.19
upstream, and ESP32_PLATFORM_VERSION=6.11.0 against 7.0.1 — a major. That is a separate
decision with its own compatibility question and does not belong in this bump.
images/esp-idf/Dockerfilepins the harness at2.8.1(lines 59-63). The bug that madethose pins worth having in the first place is fixed upstream as of 2.9.0, so the pins
should move to 2.9.3.
Why now
_PopenRedirectProcess._forward_ioread the redirect log in text mode while the file wasstill being appended to, so a UTF-8 sequence straddling a read boundary raised
UnicodeDecodeError. Since 2.0.0 anexcept Exceptionswallowed it: the forwarder exited 0with an empty stderr and DUT output stopped for the rest of the session, surfacing much later
as a pexpect timeout naming an unrelated test.
Fixed in espressif/pytest-embedded#426 (issue espressif/pytest-embedded#425), released in
v2.9.0on 2026-08-25. Verified in the published wheel rather than from the changelog:pytest_embedded/log.pyin 2.8.1 has noopen(logfile, 'rb'), 2.9.0 and 2.9.3 do.Consumer context: jethome-iot/jetcontrol-cpp#462, where this cost about a day of misdiagnosis
and is currently held off by a source lint banning non-ASCII in device log calls. That lint
can be dropped once the images carry the fix.
The change
images/esp-idf/Dockerfile, lines 59-63 only:Nothing else moves. Checked against PyPI metadata:
esptoolpytest-embedded-serial-espstill requiresesptool<6,>=5.2, unchanged between 2.8.1 and 2.9.3pytestpytest>=7.0pytest-timeoutpytest-covrequires_pythonis>=3.10in both releases, and the image runs 3.12.3.Because esptool does not move, the assertion at line 102
(
grep -qx 'esptool==5.3.1' /opt/esp/python-packages.txt) stays as it is.Scope: one Dockerfile
The harness is pinned in
images/esp-idf/Dockerfileand nowhere else.images/esp-matter/Dockerfilehas no harness pins — it isFROMthe esp-idf image and picksthe new versions up on rebuild. Its line 140 reads
^esptool==out of the base's/opt/esp/python-packages.txt; since esptool is unchanged, that check is unaffected.images/platformio/Dockerfileis unrelated to the harness.Verification after the bump
Bumping the number is not the same as getting the fix, so please confirm the behaviour rather
than the version string: build the image, then emit a non-ASCII character from a DUT in a
QEMU run — a single
printfwith an em dash (U+2014) in the device output is enough — andcheck that the run completes instead of stopping mid-stream. On 2.8.1 that reproduces as a
pexpect.exceptions.TIMEOUTwith nothing in the logs mentioning decoding.The existing
python -m pip checkand thepip freezesnapshot in the verification layercover the rest.
Unrelated observation
While checking the pins:
images/platformio/DockerfilehasPIO_VERSION=6.1.18against 6.1.19upstream, and
ESP32_PLATFORM_VERSION=6.11.0against 7.0.1 — a major. That is a separatedecision with its own compatibility question and does not belong in this bump.