Skip to content

az aks get-credentials fails with Error running kubelogin: [Errno 2] No such file or directory: '' despite kubelogin correctly installed and on PATH #34091

Description

@awangptc

Describe the bug

Running az aks get-credentials against an AAD-enabled AKS cluster successfully writes the kubeconfig, but immediately after merging the context, the command prints:

Merged "" as current context in
Error running kubelogin: [Errno 2] No such file or directory: ''

This appears to come from the new automatic kubelogin-conversion behavior added in #32167 (auto-running kubelogin convert-kubeconfig -l azurecli when the kubeconfig requires device-code auth). The empty string ('') passed as the executable path suggests the internal lookup used by this feature is not resolving kubelogin's path correctly, even though kubelogin is verifiably installed and on PATH.

As a result, the automatic conversion to azurecli login mode never happens, and the generated kubeconfig is left in devicecode login mode:

users:
- name: clusterUser_<resource-group>_<cluster-name>
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - get-token
      - --environment
      - AzurePublicCloud
      - --server-id
      - <aad-server-id>
      - --client-id
      - <aad-client-id>
      - --tenant-id
      - <aad-tenant-id>
      - --login
      - devicecode
      command: kubelogin
      env: null
      installHint: |

        kubelogin is not installed which is required to connect to AAD enabled cluster.

        To learn more, please go to https://aka.ms/aks/kubelogin

This defeats the purpose of #32167, since the first kubectl command against the cluster then triggers an interactive device-code login prompt rather than transparently using the Azure CLI token as intended.

Related command

az aks get-credentials --name <cluster-name> --resource-group <resource-group> -f <config-file> --subscription <subscription> --overwrite-existing

Errors

Merged "<cluster-name>" as current context in <config-file>
Error running kubelogin: [Errno 2] No such file or directory: ''

Issue script & Debug output

I've confirmed kubelogin itself is not the problem:

$ which kubelogin
/opt/homebrew/bin/kubelogin

$ /opt/homebrew/bin/kubelogin --version
kubelogin version
git hash: v0.2.19/a9b10fbf8422f0c5b687eb58f26d7995f2fe206d
Go version: go1.26.4
Build time: 2026-06-23T17:26:47Z
Platform: darwin/arm64

$ ls -l /usr/local/bin/kubelogin
-rwxr-xr-x  1 root  wheel  59970930 Sep 16 12:33 /usr/local/bin/kubelogin

$ /usr/local/bin/kubelogin --version
kubelogin version
git hash: v0.2.19/a9b10fbf8422f0c5b687eb58f26d7995f2fe206d
Go version: go1.26.4
Build time: 2026-06-23T17:26:47Z
Platform: darwin/arm64

Both installs (Homebrew at /opt/homebrew/bin, and the one from az aks install-cli at /usr/local/bin) are the same version, both executable, and the Homebrew one correctly resolves first on PATH.

Manually running kubelogin convert-kubeconfig -l azurecli after get-credentials works around the issue completely (converting the kubeconfig from devicecode to azurecli login mode as expected), which points at the bug being in az CLI's internal invocation of kubelogin during get-credentials, not in kubelogin itself or PATH resolution in my shell.

Expected behavior

az aks get-credentials should successfully run the automatic kubelogin conversion as intended by #32167 (leaving the kubeconfig in azurecli login mode), or fail gracefully with a clear message if it genuinely can't find kubelogin — not emit an empty-path Errno 2 while silently leaving the kubeconfig in devicecode mode.

Environment Summary

$ az --version
azure-cli                         2.90.0
core                              2.90.0
telemetry                          1.1.0

Extensions:
bastion                            1.4.3
ssh                                2.0.6

Dependencies:
msal                              1.36.0
azure-mgmt-resource               24.0.0

OS: macOS (Apple Silicon, darwin/arm64)
kubelogin: v0.2.19 (installed via both Homebrew and az aks install-cli)
Related: #32167 (introduced the auto-conversion behavior), possibly related to #32313 (sporadic "kubelogin: command not found" on the same feature in CI agents)

Additional context

No response

Activity

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

    @yonzhan
    Collaborator

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

  3. x-engineering-agent commented on Sep 18, 2026

    @x-engineering-agent
    Contributor

    Bug analysis: AKS credential conversion

    Observed versus expected

    The report is sufficient for a focused core CLI fix; no additional requirements are needed. The affected command is:

    az aks get-credentials --name <cluster-name> --resource-group <resource-group> -f <config-file> --subscription <subscription> --overwrite-existing
    

    Reported context: Azure CLI/core 2.90.0, macOS Apple Silicon (darwin/arm64), an AAD-enabled AKS cluster, and kubelogin v0.2.19. The report confirms executable Homebrew and install-cli copies of kubelogin and successful manual conversion. The author's only follow-up is an acknowledgment, with no additional diagnostic facts or contrary results.

    Actual output after the successful kubeconfig merge:

    Merged "<cluster-name>" as current context in <config-file>
    Error running kubelogin: [Errno 2] No such file or directory: ''
    

    The written kubeconfig retains --login devicecode, so subsequent kubectl use prompts for device-code authentication. Expected: automatically convert the same kubeconfig selected by get-credentials to Azure CLI authentication, or give an accurate, nonfatal warning if kubelogin cannot be used.

    Source evidence and diagnosis

    Inspected current dev source at cd047807de9eee2b0e435a9113801048a8bc8e16. Target inference resolves the acs core module, not an extension.

    • commands.py:132 registers the handwritten aks_get_credentials handler.
    • custom.py:1899-1975 selects the effective file, merges credentials, checks uses_kubelogin_devicecode, and invokes subprocess.run(["kubelogin", "convert-kubeconfig", "-l", "azurecli"], cwd=os.path.dirname(path), check=True) after a successful which("kubelogin") check.
    • For a bare relative filename such as cluster.config, os.path.dirname(path) is empty. Passing that as cwd explains an empty-path FileNotFoundError before conversion can run. The executable in this source is the literal nonempty string kubelogin; the reported empty string is not evidence that executable discovery returned an empty executable.
    • _print_or_merge_credentials, custom.py:2145-2179 already supports a bare filename and treats - as stdout-only. Its successful merge does not make an empty subprocess working directory valid.
    • The conversion argv also never passes the effective kubeconfig path. Changing working directory is not explicit kubeconfig selection. Merely replacing empty cwd with . can still leave a custom --file target unconverted or convert a different default/environment-selected file.

    This is a source-supported client-side path-handling defect. The report's filename is a placeholder, so its exact relative/absolute form is not independently confirmed. A bare relative output file provides a concrete regression scenario for the observed error. No live-cluster reproduction or tests were run during this triage; the report's suggested PATH-lookup cause and related-issue hypotheses are not treated as established facts.

    Focused implementation handoff

    1. In aks_get_credentials, explicitly pass the effective output kubeconfig to kubelogin, using its supported --kubeconfig option. Avoid an empty working directory and avoid reinterpreting a relative kubeconfig path after a directory change. Resolve the conversion target consistently with the already-selected file; do not change CLI file-precedence semantics.
    2. Preserve stdout-only --file - behavior: do not run conversion against an unrelated/default file or contaminate emitted YAML. Keep existing devicecode detection and the nonfatal missing-executable/nonzero-exit warning behavior, and retain list-based subprocess invocation without a shell.
    3. Preserve explicit --file precedence over KUBECONFIG, the existing first-entry KUBECONFIG behavior, default-file behavior, context/overwrite/admin semantics, and the existing merge permission, atomic-write, and symlink protections. Keep scope to this runtime path; no authentication redesign or generated command-schema changes are indicated.

    Regression and scenario coverage for the queued job

    Extend the existing acs tests (including tests/latest/test_custom.py) and appropriate existing credential scenarios. Exercise the handler with devicecode credentials and controlled service responses. Include a real subprocess boundary with a controlled kubelogin executable, or equivalent existing runtime scenario coverage, so an invalid cwd is not hidden by mocking subprocess.run alone.

    Cover bare filename, ./filename, nested relative and absolute paths, and paths containing spaces; explicit --file with a conflicting KUBECONFIG; default and first-entry KUBECONFIG selection; stdout -; non-devicecode credentials; missing kubelogin; and nonzero conversion exit. Assert the intended output is converted to azurecli mode while an unrelated default kubeconfig remains unchanged. Confirm successful merging and warning behavior remain compatible. The implementation job should run the repository's existing focused validation and report its actual results; these are planned checks, not claimed passing tests.

    Impact, workaround, and next action

    Credential retrieval succeeds, but automatic authentication conversion fails or can target the wrong file, leaving interactive devicecode login in place. The reported platform is macOS; the bare-relative-path defect is not inherently macOS-specific. Manual conversion is a reporter-confirmed workaround. For a custom output file, explicitly target that same file, for example kubelogin convert-kubeconfig --kubeconfig <config-file> -l azurecli.

    Next action: enqueue one focused Foundry implementation job for this core module against dev. No extension tracker is required. This triage only posts the analysis and queues durable work; it does not modify source, execute the implementation job, run tests, or wait for CI.

    The affected handler is handwritten custom.py code registered in commands.py; a fix confined to that handler and its tests should not alter generated AAZ output. If investigation reaches generated commands or durable model inputs, follow the complete repository-owned generation protocol below instead of manually patching generated artifacts.

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

    [AKS] Fix #34091: `az aks get-credentials`: Fix kubelogin conversion for explicit kubeconfig paths
    

    Keep the backticks around the command and the Fix #34091: prefix. You may only adjust the wording after the command (the final summary) if the fix changes; the [AKS] 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 Azure/azure-cli#34091.
    • 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. [AKS] `az <command>`: <note>.
    • Keep the template checklist and tick the items you've satisfied.

    Mandatory Codegen execution protocol

    Before editing implementation files, determine whether the affected acs 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. X Engineering Agent 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 acs --cli-path <azure-cli>
    
    # New/imported command model only:
    aaz-dev cli generate --spec <specification-name> --module acs

    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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    AADAKSaz aks/acs/openshiftAuto-AssignAuto assign by botService AttentionThis issue is responsible by Azure service team.act-observability-squadbugThis 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