Azure / Azure/azure-cli-extensions
[serial-console] Garbled output: bytes printed as repr() instead of decoded text
- Dominant language
- Python
- Stars
- 454
- Forks
- 1.7k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 64
Description
### Describe the bug
When connecting to a VM (or VMSS instance) via `az serial-console connect`, the console output is rendered as Python `bytes` repr instead of decoded text. ANSI escape sequences and CR/LF are shown as literal `\x1b[0;32m`, `\r\n`, and the entire stream is wrapped in `b'...'`, making the serial console unusable.
The root cause is in `src/serial-console/azext_serialconsole/custom.py`, in the `on_message` callback inside `SerialConsole.connect()`:
```python
def on_message(_, message):
if GV.first_message:
...
else:
PC.print(message) # message can be `bytes`, gets stringified via repr()
```
The Azure serial console websocket endpoint sends frames that arrive as `bytes` from `websocket-client` 1.3.1 (the version vendored with the extension on Python 3.13). `PC.print` ultimately calls Python's built-in `print()` on the `bytes` object, which produces the `b'...'` repr instead of decoded text.
A one-line fix decoding the message resolves it:
```python
def on_message(_, message):
if isinstance(message, (bytes, bytearray)):
message = bytes(message).decode("utf-8", errors="replace")
if GV.first_message:
...
else:
PC.print(message)
```
I patched my local install with this and the console now renders correctly with proper newlines and ANSI colors.
### Related command
`az serial-console connect`
### Errors
No exception is raised. The output looks like this (sample, sensitive parts redacted):
```
b'\r\n[ 2135.909432] cloud-init[3293]: The system is finally up, after 2135.90 seconds\r\n\x1b[0;32m OK \x1b[0m] Finished \x1b[0;1;39mcloud-init-final.service\x1b[0m - Cloud-init: Final Stage.\r\n...'
```
(every line of the boot log / login prompt is similarly wrapped)
### Issue script & Debug output
```
export TERM=xterm-256color
az serial-console connect \
--resource-group \
--name \
--instance-id \
--debug
```
The `--debug` log shows the websocket connection succeeds (no errors). The garbled output begins immediately after `first_message` is consumed and subsequent frames are forwarded to `PC.print`.
### Expected behavior
Serial console output should be written to the terminal as decoded text so that ANSI escapes and CR/LF are interpreted by the user's terminal emulator, producing a normal cloud-init / login boot log.
### Environment Summary
\`\`\`
azure-cli 2.85.0
core 2.85.0
telemetry 1.1.0
Extensions:
serial-console 1.0.0b3
azure-devops 1.0.2
containerapp 1.3.0b4
databricks 1.3.1
k8s-configuration 2.3.0
k8s-extension 1.7.0
serviceconnector-passwordless 3.3.6
Python location '/opt/homebrew/Cellar/azure-cli/2.85.0/libexec/bin/python'
Python (Darwin) 3.13.12 (main, Feb 3 2026, 17:53:27) [Clang 17.0.0 (clang-1700.6.3.2)]
Installed via Homebrew on macOS 15 (Apple Silicon).
\`\`\`
Vendored \`websocket-client\` version inside the extension: \`1.3.1\`.
### Additional context
- Reproducible 100% of the time when connecting to any Linux VM/VMSS instance with serial console enabled.
- Workaround: monkey-patch \`~/.azure/cliextensions/serial-console/azext_serialconsole/custom.py\` with the \`isinstance(message, bytes)\` decode shown above, and delete \`__pycache__/\`.
- Likely root cause: \`websocket-client\` >= 1.0 returns \`bytes\` for binary frames (or text frames received without a UTF-8 charset hint); the extension was written assuming \`str\`. A version pin of \`websocket-client < 1.0\` would also work but is not future-proof.
- Will follow up with a PR containing the one-line fix.
Contributor guide
Assessment
This issue has not been assessed yet.