Azure / Azure/azure-cli-extensions

[serial-console] Garbled output: bytes printed as repr() instead of decoded text

Open
#9,796 4 comments 0 reactions 0 assignees View on GitHub
customer-reported question Serial Console Service Attention
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.