Skip to content

Galaxy incorrectly reports deps already installed #5137

Description

@ben-pearce

Cannot find duplicate matching issue
Version: v26.6.0

Summary

When running GitHub action, galaxy incorrectly reports deps already installed.

Issue Type
  • Bug Report
OS / ENVIRONMENT
ansible-lint --version
ansible-lint 26.6.0 using ansible-core:2.21.2 ansible-compat:26.6.0 ruamel-yaml:0.19.1 ruamel-yaml-clib:None

OS: Ubuntu latest (24.04) GHA hosted runner.

  • ansible installation method: GHA
  • ansible-lint installation method: GHA
STEPS TO REPRODUCE

Fresh ansible playbooks repository with the following structure:

ansible
├── playbook.yml
├── requirements.yml
└── roles
    ├── common
    │   ├── files
    │   │   ...
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml

A requirements.yml with the following content:

collections:
  - name: ansible.posix
    version: 2.2.2
  - name: community.general
    version: 13.2.0
  - name: community.docker
    version: 5.2.1
The GitHub actions workflow
name: ✨ Lint and Format YAML

on:
  push:
    paths:
      - 'ansible/**.yml'
      - '.github/workflows/ansible-lint.yml'
    branches: [ "main" ]

concurrency:
  group: push

jobs:
  generate:
    runs-on: ubuntu-latest
    if: ${{ !contains(github.event.head_commit.message, 'chore(deps)') }}

    steps:
      - name: 📥 Checkout Repository
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

      - name: ✨ Run ansible-lint
        uses: ansible/ansible-lint@262624cd0ab22a4221293216856c59671ce7aa5e # v26.6.0
        with:
          working_directory: ansible
          setup_python: "true"
          requirements_file: "requirements.yml"
Desired Behavior

A compliant repository in subdirectory ansible passes with zero warnings or errors.

Actual Behavior

Galaxy install step reports zero dependencies to install.
Following ansible lint run reports missing dependencies:


Install role and collection dependencies from requirements file
12s
Run ansible-galaxy install -r requirements.yml
    
  Starting galaxy collection install process
  Nothing to do. All requested collections are already installed. If you want to reinstall them, consider using `--force`.
Run ansible-lint
12s
Run exit_code=0
    
  WARNING  Listing 10 violation(s) that are fatal
  Error: couldn't resolve module/action 'community.docker.docker_container_exec'. This often indicates a misspelling, missing collection, or incorrect module path.
  Error: couldn't resolve module/action 'community.general.ini_file'. This often indicates a misspelling, missing collection, or incorrect module path.
  Error: couldn't resolve module/action 'community.general.ini_file'. This often indicates a misspelling, missing collection, or incorrect module path.
  Error: couldn't resolve module/action 'ansible.posix.authorized_key'. This often indicates a misspelling, missing collection, or incorrect module path.

...

The linter errors are a symptom of what I suspect is an issue with the Galaxy install step.

To add further validation to my claim, the following workaround / hack resolves the issue:

The GitHub actions workflow
name: ✨ Lint and Format YAML

on:
  push:
    paths:
      - 'ansible/**.yml'
      - '.github/workflows/ansible-lint.yml'
    branches: [ "main" ]

concurrency:
  group: push

jobs:
  generate:
    runs-on: ubuntu-latest
    if: ${{ !contains(github.event.head_commit.message, 'chore(deps)') }}

    steps:
      - name: 📥 Checkout Repository
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

      - name: ✨ Run ansible-lint
        uses: ansible/ansible-lint@262624cd0ab22a4221293216856c59671ce7aa5e # v26.6.0
        with:
          working_directory: ansible
          setup_python: "true"
          # The dirty hack: inject `--force` param into galaxy install invocation.
          requirements_file: "requirements.yml --force"

Activity

  1. vinta commented on Aug 8, 2026

    @vinta

    I hit the same failure and traced it to a PATH mismatch between the two steps of the action. Details below in case they help, plus a workaround that avoids the quoting hack.

    What the pinned versions have in common

    Your requirements.yml pins ansible.posix 2.2.2, community.general 13.2.0, and community.docker 5.2.1. Those are exactly the versions bundled in the ansible 14.2.0 package. Mine was community.general 13.2.0 alone, with the same result.

    Where the bundled copy comes from

    actions/runner-images provisions ansible with pipx install ansible-core followed by pipx inject ansible-core ansible (images/ubuntu/scripts/build/install-pipx-packages.sh), so an ubuntu-latest runner carries the full ansible package and its bundled collections in the pipx venv, with ansible-galaxy on PATH via /opt/pipx_bin.

    Why the action's own ansible-galaxy is not the one that runs

    The install step runs uv tool install --with-executables-from ansible-core "ansible-lint[lock] @ ...", and the log reports:

    Installed 1 executable: ansible-lint
    

    Only ansible-lint is exposed, so ansible-galaxy install -r <requirements_file> in the next step resolves to the runner's pipx-injected ansible. That resolver sees the bundled collections, decides the exact pins are satisfied, and prints Nothing to do without writing anything into ~/.ansible/collections. ansible-lint then runs inside the uv tool environment, which has ansible-core only, and cannot resolve the modules.

    I should be clear about which parts are observed and which are inferred. Observed, and reproduced on two runs of the same commit with ansible/ansible-lint@v26.4.0 (ansible-lint 26.4.0, ansible-core 2.21.2):

    • A pin matching a bundled version produces Nothing to do on a fresh runner and the collection is never installed.
    • Changing the pin to a non-bundled version (community.general 13.1.0) makes the same step download and install normally, and the lint run passes.
    • A clean local environment with the same ansible-core 2.21.2 installs 13.2.0 without complaint, so this is not a resolver or Galaxy metadata problem.

    Inferred: that the binary running in the requirements step is specifically the pipx one. That is consistent with the Installed 1 executable line and with how the runner image provisions ansible, but I did not print which ansible-galaxy to confirm it directly.

    Workaround without modifying the input string

    Rather than passing --force through requirements_file, dropping the input and installing in an explicit step works and keeps the input's contract intact:

    - name: Install collection dependencies
      run: ansible-galaxy collection install -r playbooks/collections/requirements.yml --force
    
    - name: Run ansible-lint
      uses: ansible/ansible-lint@v26.4.0
      with:
        args: playbooks/

    That run installs community.general:13.2.0 into /home/runner/.ansible/collections/... and lint passes.

    Possible fixes upstream

    Adding --force to the action's ansible-galaxy install invocation is the smallest change. Installing the collections with the same ansible-core that later runs ansible-lint would address the underlying mismatch, since the two steps currently disagree about which environment defines "installed".

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

    bugnewTriage required

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions