mpremote cat hangs on Windows interactive console with Unicode content
Port, board and/or hardware
Host Windows (any hardware)
MicroPython version
- mpremote 1.27.0
Reproduction
-
On Windows, have a MicroPython device with a file containing Unicode text:
/unicode_test/नेपाली_नाम.txt -
Run
mpremote catinteractively in PowerShell (NOT piped or captured):mpremote cat :/unicode_test/नेपाली_नाम.txt -
The command hangs indefinitely. Even with
PYTHONIOENCODING=utf-8set, it still hangs. -
Press Ctrl-C to interrupt.
Observations
The same command works correctly when:
- Output is piped:
mpremote cat :file.txt > output.txt - Output is captured by subprocess:
subprocess.run([...], capture_output=True) - Running on Linux (even in WSL2 on the same machine)
The hang ONLY occurs when stdout is a real Windows console (isatty=True).
Expected behaviour
$ mpremote cat :/unicode_test/नेपाली_नाम.txt
Nepali Name - नेपाली नाम
This file tests Nepali (Devanagari) script.
Script: Devanagari (Nepali variant)
Vowels: अ आ इ ई उ ऊ ऋ ए ऐ ओ औ
Consonants: क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न
...
for test files see : [https://github.com/[Josverl/unicode_mpy](https://github.com/Josverl/unicode_mpy)
https://github.com/Josverl/unicode_mpy/tree/main/test_data/South_Asian_Indic
### Observed behaviour
The command hangs indefinitely when run interactively on Windows with Unicode content. Ctrl-C shows the following traceback:
Traceback (most recent call last):
File "...\mpremote\main.py", line 614, in main
handler_func(state, args)
File "...\mpremote\commands.py", line 421, in do_filesystem
state.transport.fs_printfile(path)
File "...\mpremote\transport.py", line 129, in fs_printfile
self.exec(cmd, data_consumer=stdout_write_bytes)
File "...\mpremote\transport_serial.py", line 309, in exec
ret, ret_err = self.exec_raw(command, data_consumer=data_consumer)
File "...\mpremote\transport_serial.py", line 296, in exec_raw
return self.follow(timeout, data_consumer)
File "...\mpremote\transport_serial.py", line 204, in follow
data = self.read_until(1, b"\x04", timeout=timeout, data_consumer=data_consumer)
File "...\mpremote\transport_serial.py", line 146, in read_until
data_consumer(new_data)
File "...\mpremote\transport.py", line 36, in stdout_write_bytes
sys.stdout.buffer.flush()
KeyboardInterrupt
### Additional Information
**Initial hypothesis (DISPROVEN):** The hang was suspected to be in `stdout_write_bytes()`:
```python
def stdout_write_bytes(b):
sys.stdout.buffer.write(b)
sys.stdout.buffer.flush() # <-- Suspected to hang
Test result: A standalone Python script calling sys.stdout.buffer.write() + flush() with identical Unicode content does NOT hang.
Actual cause: The hang is NOT in CPython's stdout handling. The issue is elsewhere in mpremote, possibly:
- Different code path when
stdout.isatty()is True vs False - Threading/synchronization issues between reader/writer threads
- Windows console API interaction issues
- Serial/socket transport blocking behavior
Possibly Related Issues
- https://github.com/micropython/micropython/issues/15228 - Unable to print unicode characters when running repl with mpremote
Code of Conduct
Yes, I agree
`mpremote mip install` hangs when uploading files
Port, board and/or hardware
STM32 port on a NUCLEO-144--F767ZI
MicroPython version
MicroPython v1.27.0-preview.440.ga6864109db on 2025-11-23; NUCLEO-F767ZI with STM32F767
Reproduction
- (Optional) Perform a mass erase on all flash blocks.
- Build main firmware and mboot, then upload image to the board with
deploy-stlink - Reboot the board
- Run
mpremote mip install unittest - Wait until it hangs
Expected behaviour
mpremote mip should install the required package
Observed behaviour
The upload process hangs at random intervals, and when stopping it via CTRL+C the traceback is as follows (the process was stopped after a few minutes of being stuck at 13%):
Traceback (most recent call last):
File "/home/agatti/src/micropython/ports/stm32/../../tools/mpremote/mpremote.py", line 6, in <module>
sys.exit(main.main())
~~~~~~~~~^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/main.py", line 614, in main
handler_func(state, args)
~~~~~~~~~~~~^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/mip.py", line 206, in do_mip
_install_package(
~~~~~~~~~~~~~~~~^
state.transport,
^^^^^^^^^^^^^^^^
...<4 lines>...
args.mpy,
^^^^^^^^^
)
^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/mip.py", line 169, in _install_package
_install_json(transport, package, index, target, version, mpy)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/mip.py", line 131, in _install_json
_download_file(transport, file_url, fs_target_path)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/mip.py", line 99, in _download_file
transport.fs_writefile(dest, data, progress_callback=show_progress_bar)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/transport.py", line 163, in fs_writefile
self.exec("w(" + repr(chunk) + ")")
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/transport_serial.py", line 309, in exec
ret, ret_err = self.exec_raw(command, data_consumer=data_consumer)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/transport_serial.py", line 295, in exec_raw
self.exec_raw_no_follow(command)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/transport_serial.py", line 273, in exec_raw_no_follow
return self.raw_paste_write(command_bytes)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "/home/agatti/src/micropython/tools/mpremote/mpremote/transport_serial.py", line 228, in raw_paste_write
data = self.serial.read(1)
File "/usr/lib/python3.13/site-packages/serial/serialposix.py", line 565, in read
ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyboardInterrupt
The firmware is still waiting for data to arrive on the serial port when mpremote seems to be stuck:
^C
Program received signal SIGINT, Interrupt.
mp_hal_stdin_rx_chr () at mphalport.c:53
53 for (;;) {
08:14:08 mp_hal_stdin_rx_chr > bt
#0 mp_hal_stdin_rx_chr () at mphalport.c:53
#1 0x08068aec in mp_reader_stdin_readbyte (data=0x2007ff74)
at ../../shared/runtime/pyexec.c:255
#2 0x08023164 in next_char (lex=lex@entry=0x20037b50) at ../../py/lexer.c:174
#3 0x08023456 in parse_string_literal (lex=0x20037b50, is_raw=false,
is_fstring=false) at ../../py/lexer.c:413
#4 mp_lexer_to_next (lex=lex@entry=0x20037b50) at ../../py/lexer.c:696
#5 0x0802443c in mp_parse (lex=lex@entry=0x20037b50,
input_kind=input_kind@entry=MP_PARSE_FILE_INPUT) at ../../py/parse.c:1167
#6 0x08068be8 in parse_compile_execute (source=source@entry=0x2007ff7c,
input_kind=input_kind@entry=MP_PARSE_FILE_INPUT,
exec_flags=exec_flags@entry=65) at ../../shared/runtime/pyexec.c:111
#7 0x08068d90 in do_reader_stdin (c=65) at ../../shared/runtime/pyexec.c:324
#8 pyexec_raw_repl () at ../../shared/runtime/pyexec.c:567
#9 0x080730d4 in stm32_main (reset_mode=<optimized out>) at main.c:718
#10 <signal handler called>
in fact, reconnecting to the serial port will find the interpreter still waiting for data to arrive.
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree