Skip to content

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

@muram

Description

@muram

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():

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:

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 <rg> \
  --name <vmss-name> \
  --instance-id <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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Serial ConsoleService AttentionThis issue is responsible by Azure service team.customer-reportedIssues that are reported by GitHub users external to the Azure organization.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions