{"record":{"id":"e997d6e7dcbcf7d2","repo":"ansible/ansible","slug":"expecting-requirements-file-to-be-a-dict-with-the","errorCode":null,"errorMessage":"Expecting requirements file to be a dict with the key 'collections' that contains a list of collections to install","messagePattern":"Expecting requirements file to be a dict with the key 'collections' that contains a list of collections to install","errorType":"exception","errorClass":"AnsibleError","httpStatus":null,"severity":"error","filePath":"lib/ansible/cli/galaxy.py","lineNumber":808,"sourceCode":"                return [GalaxyRole(self.galaxy, self.lazy_role_api, **role)]\n            else:\n                b_include_path = to_bytes(requirement[\"include\"], errors=\"surrogate_or_strict\")\n                if not os.path.isfile(b_include_path):\n                    raise AnsibleError(\"Failed to find include requirements file '%s' in '%s'\"\n                                       % (to_native(b_include_path), to_native(requirements_file)))\n\n                with open(b_include_path, 'rb') as f_include:\n                    try:\n                        return [GalaxyRole(self.galaxy, self.lazy_role_api, **r) for r in\n                                (RoleRequirement.role_yaml_parse(i) for i in yaml_load(f_include))]\n                    except Exception as e:\n                        raise AnsibleError(\"Unable to load data from include requirements file: %s %s\"\n                                           % (to_native(requirements_file), to_native(e)))\n\n        if isinstance(file_requirements, list):\n            # Older format that contains only roles\n            if not allow_old_format:\n                raise AnsibleError(\"Expecting requirements file to be a dict with the key 'collections' that contains \"\n                                   \"a list of collections to install\")\n\n            for role_req in file_requirements:\n                requirements['roles'] += parse_role_req(role_req)\n\n        elif isinstance(file_requirements, dict):\n            # Newer format with a collections and/or roles key\n            extra_keys = set(file_requirements.keys()).difference(set(['roles', 'collections']))\n            if extra_keys:\n                raise AnsibleError(\"Expecting only 'roles' and/or 'collections' as base keys in the requirements \"\n                                   \"file. Found: %s\" % (to_native(\", \".join(extra_keys))))\n\n            for role_req in file_requirements.get('roles') or []:\n                requirements['roles'] += parse_role_req(role_req)\n\n            requirements['collections'] = [\n                Requirement.from_requirement_dict(\n                    self._init_coll_req_dict(collection_req),","sourceCodeStart":790,"sourceCodeEnd":826,"githubUrl":"https://github.com/ansible/ansible/blob/9cf16a4aca7898481c257f1e17ad28d0b67b1f85/lib/ansible/cli/galaxy.py#L790-L826","documentation":"Raised by _parse_requirements_file when the requirements YAML is a plain list (the old role-only format) but allow_old_format is False. Collection-oriented subcommands (install via _require_one_of_collections_requirements, download, etc.) pass allow_old_format=False and therefore demand the modern dict format with 'collections'/'roles' keys.","triggerScenarios":"Running 'ansible-galaxy collection install -r requirements.yml' where requirements.yml is a bare list of roles ('- src: git+...'), or 'ansible-galaxy install -r file.yml' in the implicit-collection mode that calls _parse_requirements_file with allow_old_format=False at lib/ansible/cli/galaxy.py:808.","commonSituations":"Teams upgrade ansible and reuse an old role-only requirements.yml with 'ansible-galaxy collection install'; CI scripts that switched from 'ansible-galaxy install' to 'collection install' without migrating the requirements file format.","solutions":["Convert the file to the modern format: wrap roles under a 'roles:' key and put collections under 'collections:'.","If you only want roles installed, invoke 'ansible-galaxy role install -r requirements.yml' which still allows the old list format.","If both roles and collections are needed, use 'ansible-galaxy install -r requirements.yml' (implicit mode) with a dict-format file containing both keys."],"exampleFix":"# before (requirements.yml)\n- src: geerlingguy.docker\n\n# after\nroles:\n  - name: geerlingguy.docker\ncollections:\n  - community.general\n","handlingStrategy":"validation","validationCode":"import yaml\n\ndata = yaml.safe_load(open(\"requirements.yml\"))\nif isinstance(data, list):\n    raise SystemExit(\"requirements.yml uses the old role-list format; \"\n                     \"wrap entries under a 'roles:' key (and 'collections:' for collections)\")\n","typeGuard":"def is_modern_requirements(data) -> bool:\n    return isinstance(data, dict) and ('roles' in data or 'collections' in data)\n","tryCatchPattern":null,"preventionTips":["Standardize on the dict format with roles:/collections: keys across all repos.","Use 'ansible-galaxy role install -r' when deliberately consuming old-format files.","Add a preflight schema check in CI before any 'collection install -r' call."],"tags":["ansible-galaxy","requirements","collections","format-migration"],"backgroundTag":null,"analyzedSha":"9cf16a4aca7898481c257f1e17ad28d0b67b1f85","analyzedAt":"2026-08-15T00:15:47.100Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}