Skip to content

[App Service] az webapp ssh silently exits on macOS with Python 3.14 and Invoke 2.2.0 #34005

Description

Describe the bug

On macOS with Azure CLI 2.89.1 installed by Homebrew, az webapp ssh establishes the App Service tunnel and opens a Paramiko SSH channel, but immediately closes without displaying an error. The command exits with status 0.

With --debug, the interactive session reports buffer overflow. Azure CLI catches the exception in _start_ssh_session, logs it only at INFO/debug level, closes the connection, and returns success.

The bundled Invoke 2.2.0 uses a 4-byte "HH" buffer for TIOCGWINSZ. Python 3.14 detects the 8-byte write on macOS and raises SystemError: buffer overflow. Updating Invoke to 2.2.1 fixes the command.

Upstream: pyinvoke/invoke#1038
Python 3.14 tracking: #32869

Related command

az webapp ssh --resource-group --name

Errors

No error appears normally; the command silently returns with exit status 0.

With --debug:

paramiko.transport: Secsh channel 0 opened.
paramiko.transport: [chan 0] EOF sent (0)
azure.cli.command_modules.appservice.custom: buffer overflow
Client disconnected
websocket close: Connection failure.
az_command_data_logger: exit code: 0

Issue script & Debug output

``shell
az webapp ssh
--resource-group
--name
--debug


The tunnel and SSH channel are established, followed by:

paramiko.transport: Secsh channel 0 opened.
paramiko.transport: [chan 0] EOF sent (0)
azure.cli.command_modules.appservice.custom: buffer overflow
Client disconnected
websocket close: Connection failure.
az_command_data_logger: exit code: 0


Invoke 2.2.0's `invoke/terminals.py` contains:

```python
fmt = "HH"
buf = struct.pack(fmt, 0, 0)
result = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)

Invoke 2.2.1 uses the correct 8-byte "HHHH" structure. Installing 2.2.1 into Azure CLI's environment makes the same command work.

Expected behavior

The command should maintain an interactive SSH session. If terminal creation fails, Azure CLI should display the exception and return a nonzero status instead of silently closing with status 0.

Environment Summary

azure-cli 2.89.1
core 2.89.1
telemetry 1.1.0

Installation: Homebrew
Python location: /opt/homebrew/Cellar/azure-cli/2.89.1/libexec/bin/python
Python: 3.14.7
Bundled Invoke: 2.2.0
Fabric: 3.2.2
OS: macOS 26.6.2
Architecture: arm64

Additional context

Homebrew's current Azure CLI 2.89.1 formula depends on Python 3.14 and packages Invoke 2.2.0.

Working dependency update:

"$(brew --prefix azure-cli)/libexec/bin/python" \
  -m pip install --ignore-installed "invoke==2.2.1"

Another workaround is az webapp create-remote-connection plus the system SSH client.

Suggested fixes:

  1. Package a Python 3.14-compatible Invoke version.
  2. Do not suppress the session exception and report success when SSH failed.

Activity

  1. added
    bugThis issue requires a change to an existing behavior in the product in order to be resolved.
    on Aug 27, 2026
  2. yonzhan commented on Aug 27, 2026

    @yonzhan
    Collaborator

    Thank you for opening this issue, we will look into it.

  3. x-engineering-agent commented on Aug 27, 2026

    @x-engineering-agent
    Contributor

    Bug Analysis

    az webapp ssh (implemented in src/azure-cli/azure/cli/command_modules/appservice/custom.py, function _start_ssh_session) establishes an App Service tunnel and opens a Paramiko SSH channel, then hands off to an interactive terminal via the bundled invoke/fabric libraries.

    On macOS with Python 3.14 (e.g. Homebrew's azure-cli 2.89.1 build), the bundled invoke==2.2.0 calls fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, struct.pack('HH', 0, 0)) — a 4-byte buffer — in invoke/terminals.py. Python 3.14 added stricter ioctl buffer-size validation and raises SystemError: buffer overflow for the 8-byte TIOCGWINSZ response landing in that 4-byte buffer. invoke fixed this upstream by switching to the correct 'HHHH' (8-byte) format in 2.2.1 (pyinvoke/invoke#1038).

    The real Azure CLI bug is that _start_ssh_session catches this (and any other) exception from the interactive session, logs it only at INFO/DEBUG level, closes the connection, and lets the command return exit code 0 as if the SSH session succeeded. Users get no visible error and a misleading success exit status.

    Fix: in _start_ssh_session (or wherever the interactive session's exception is caught), do not swallow the exception silently — surface it to the user (e.g. raise a CLIError/AzureResponseError with the underlying message, or at minimum log it at ERROR level) and ensure the process exits non-zero when the interactive terminal fails to start, instead of returning success. Do not attempt to vendor a newer invoke version as part of this fix — that is a packaging/dependency concern outside this PR's scope; focus only on not masking the failure.

    Reproduction: macOS, Python 3.14.7, Azure CLI 2.89.1 (Homebrew), bundled Invoke 2.2.0. Running az webapp ssh --resource-group <rg> --name <app> with --debug shows azure.cli.command_modules.appservice.custom: buffer overflow followed by az_command_data_logger: exit code: 0.

    Use this EXACT PR title: [AppService] Fix #34005: az webapp ssh: Report SSH session failures instead of exiting 0

    Mandatory Codegen execution protocol

    Before editing implementation files, determine whether the affected appservice command is AAZ-generated. Files under aaz/<profile>/ are generated output and must never be patched directly, including by an AI agent. Check out Azure/aaz beside Azure/azure-rest-api-specs, Azure/aaz-dev-tools, and the downstream repository. API-schema defects start in the specification; command naming, grouping, arguments, API-version selection, help, and examples belong in the durable Azure/aaz command model; non-modelable client behavior belongs in a handwritten subclass or wrapper in custom.py, registered from commands.py. Agent Assist creates and promotes the corresponding durable Azure/aaz source pull request before it promotes downstream generated output.

    Follow the Azure CLI repository's Codegen workflow and the aaz-dev setup documentation. Set up the checked-out repositories with azdev setup. Use generate only when importing or redesigning command models from Swagger/TypeSpec. For an existing module whose durable Azure/aaz model has been updated, render that model with regenerate:

    aaz-dev cli regenerate --name appservice --cli-path <azure-cli>
    
    # New/imported command model only:
    aaz-dev cli generate --spec <specification-name> --module appservice

    You MUST actually run the generator; do not merely describe it or imitate its output. If the AAZ/specification checkout, local source change, credentials, or generator is unavailable, stop and report the blocker instead of editing generated files. Inspect _aaz_info provenance and the complete regenerated diff, then run focused azdev style, azdev linter, and azdev test validation. For an extension, also update its version and HISTORY.rst, preserve azext_metadata.json compatibility, and let release automation update src/index.json.

    PR title & description format (required)

    This repo enforces a PR format (guide). Please author the PR exactly as follows or CI's Check the Format of Pull Request Title and Content will fail.

    Use this EXACT PR title (copy verbatim, do not reword):

    [AppService] Fix #34005: `az webapp ssh`: Report SSH session failures instead of exiting 0
    

    Keep the backticks around the command and the Fix #34005: prefix. You may only adjust the wording after the command (the final summary) if the fix changes; the [AppService] prefix, issue link, and backticked command must stay.

    Description — follow the PR template and fill in:

    • Link the issue — start the Description with a closing keyword so the PR auto-links and closes it: Fixes #34005.
    • Related command — the az ... command this affects.
    • Description (mandatory) — why the bug happens, what you changed, and the resulting behavior.
    • Testing Guide — example command(s) showing the fix works.
    • History Notes — leave the title to drive the history note, or add extra lines in the same format (component in brackets + the command in backticks), e.g. [AppService] `az <command>`: <note>.
    • Keep the template checklist and tick the items you've satisfied.
  4. x-engineering-agent commented on Aug 27, 2026

    @x-engineering-agent
    Contributor

    Started a Copilot task in a0x1ab/azure-cli using claude-sonnet-4.6: https://github.com/a0x1ab/azure-cli/tasks/1e6a0669-428c-4e10-bbe7-8e33a0db4090

  5. added a commit that references this issue on Aug 27, 2026
    59a86b7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Auto-AssignAuto assign by botService AttentionThis issue is responsible by Azure service team.Web Appsaz webappact-observability-squadapp-service-generalapp-service-networkingbugThis issue requires a change to an existing behavior in the product in order to be resolved.customer-reportedIssues that are reported by GitHub users external to the Azure organization.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions