Skip to content

[serial-console] Fix garbled console output by decoding binary websocket frames#9797

Open
muram wants to merge 2 commits intoAzure:mainfrom
muram:fix/serial-console-bytes-decode
Open

[serial-console] Fix garbled console output by decoding binary websocket frames#9797
muram wants to merge 2 commits intoAzure:mainfrom
muram:fix/serial-console-bytes-decode

Conversation

@muram
Copy link
Copy Markdown

@muram muram commented Apr 19, 2026

Related command

az serial-console connect

Description

Fixes #9796.

The serial-console extension's on_message callback in SerialConsole.connect() assumed websocket frames were always str. Newer versions of websocket-client (>= 1.0, including the vendored 1.3.1) return bytes for binary frames, which the extension passed straight into Python's built-in print() — producing a bytes repr (b'...\r\n\x1b[0;32m...') in the user's terminal instead of decoded text. This makes the serial console unusable on recent Python/websocket-client combinations (reliably reproduced on Python 3.13).

Sample of the broken output before this fix:

b'\r\n[ 2135.909432] cloud-init[3293]: The system is finally up...\r\n\x1b[0;32m  OK  \x1b[0m] Finished cloud-init...'

Change

In src/serial-console/azext_serialconsole/custom.py, decode bytes/bytearray to str (UTF-8 with errors="replace" for safety) before forwarding the message to PC.print. After this change, ANSI escapes and CR/LF are interpreted by the user's terminal as intended and the serial console renders normally.

def on_message(_, message):
    if isinstance(message, (bytes, bytearray)):
        message = bytes(message).decode("utf-8", errors="replace")
    ...

Versioning

  • Bumps serial-console from 1.0.0b3 to 1.0.0b4.
  • Adds a HISTORY.rst entry.

Testing

  • Repro before fix: az serial-console connect --resource-group <rg> --name <vmss> --instance-id <id> shows literal b'...' blob instead of console output.
  • After applying this patch (and clearing __pycache__), the same command renders the cloud-init / login boot log normally with proper newlines and colors.
  • Verified on:
    • macOS 15 (Apple Silicon), Homebrew azure-cli 2.85.0, Python 3.13.12
    • Connecting to a Linux VMSS instance with serial console enabled

Notes

  • This is a minimal, behavior-preserving fix — no API changes, no dependency changes.
  • Pinning websocket-client < 1.0 would also "fix" the symptom but is not future-proof and conflicts with downstream Python compatibility.

…ket frames

The serial-console extension's on_message callback assumed websocket
frames were always str. Newer versions of websocket-client (>= 1.0)
return bytes for binary frames, which the extension passed straight
into print() and got rendered as a Python bytes repr (b'...\r\n
\x1b[0;32m...'). This makes the serial console unusable on recent
Python/websocket-client combinations (reproduced on Python 3.13 with
the vendored websocket-client 1.3.1).

Decode bytes to str inside on_message so that ANSI escapes and CR/LF
are interpreted by the user's terminal as intended.

Bumps version to 1.0.0b4 and adds a HISTORY.rst entry.

Fixes Azure#9796

Made-with: Cursor
@azure-client-tools-bot-prd
Copy link
Copy Markdown

azure-client-tools-bot-prd Bot commented Apr 19, 2026

️✔️Azure CLI Extensions Breaking Change Test
️✔️Non Breaking Changes

@yonzhan
Copy link
Copy Markdown
Collaborator

yonzhan commented Apr 19, 2026

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link
Copy Markdown
Contributor

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

@microsoft-github-policy-service microsoft-github-policy-service Bot added the customer-reported Issues that are reported by GitHub users external to the Azure organization. label Apr 19, 2026
@microsoft-github-policy-service
Copy link
Copy Markdown
Contributor

Thank you for your contribution @muram! We will review the pull request and get back to you soon.

@muram
Copy link
Copy Markdown
Author

muram commented Apr 19, 2026

@microsoft-github-policy-service agree

@yonzhan
Copy link
Copy Markdown
Collaborator

yonzhan commented Apr 19, 2026

Please fix CI issues

…conflicts

Fix CI failure on PR Azure#9797:

1. The serial-console extension pinned `websocket-client==1.3.1`, but
   recent azure-cli requires `websocket-client~=1.8.0`. Installing the
   extension into an env that already has azure-cli triggers
   `pkg_resources.ContextualVersionConflict` and `azdev extension add`
   fails. Widen the pin to `~=1.8.0` to match azure-cli and stay within
   the same major series.

2. In `.github/workflows/VersionCalPRComment.yml`, `azdev setup` runs
   after `pip install azdev` and installs azure-cli's pinned
   requirements, which downgrade transitive deps that azdev itself
   relies on:
       - azure-cli-diff-tool 0.1.1 needs requests~=2.32.3
         but azure-cli pins requests==2.33.0
       - tox 4.53.0 needs packaging>=26
         but azure-cli pins packaging==25.0
   Re-pin those two packages after `azdev setup` so the environment is
   internally consistent before the metadata generation step runs. Also
   add a non-fatal `pip check` for visibility.

Made-with: Cursor
@github-actions
Copy link
Copy Markdown
Contributor

@muram
Copy link
Copy Markdown
Author

muram commented Apr 20, 2026

Pushed a follow-up commit to fix the failing version-cal job:

  1. Real blockerpkg_resources.ContextualVersionConflict: (websocket-client 1.3.1 ..., Requirement.parse('websocket-client~=1.8.0'), {'azure-cli'}). The extension pinned websocket-client==1.3.1 while current azure-cli requires ~=1.8.0. Widened the pin in src/serial-console/setup.py to websocket-client~=1.8.0 and noted it in HISTORY.rst.

  2. Workflow tidy-up.github/workflows/VersionCalPRComment.yml "Install azdev" step ends up with two mismatched transitive deps after azdev setup -c azure-cli runs (azure-cli's requirements.py3.Linux.txt downgrades them):

    • azure-cli-diff-tool 0.1.1 requires requests~=2.32.3, but you have requests 2.33.0
    • tox 4.53.0 requires packaging>=26, but you have packaging 25.0

    These weren't the actual blocker, but they leave the env inconsistent and make the failure log noisier than it needs to be. Added a pip install --upgrade "requests~=2.32.3" "packaging>=26" after azdev setup, plus a non-fatal pip check for visibility. Happy to split the workflow change into a separate PR if maintainers prefer.

Re-running CI now.

@necusjz
Copy link
Copy Markdown
Member

necusjz commented Apr 20, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Auto-Assign Auto assign by bot customer-reported Issues that are reported by GitHub users external to the Azure organization. Serial Console

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants