Introduction
The meta-runtime rule in Ansible Lint validates the requires_ansible key in a collection's meta/runtime.yml file. This key specifies which versions of ansible-core are compatible with the collection. If the version constraint references an unsupported or end-of-life Ansible version, ansible-lint raises a schema[meta-runtime] error. This article covers the rule, correct version constraints, and best practices for collection compatibility.
Understanding meta/runtime.yml
Every Ansible collection should include a meta/runtime.yml file that declares:
requires_ansible: The minimum ansible-core version required- Plugin routing: Redirects, deprecations, and removals for modules/plugins
# meta/runtime.yml
---
requires_ansible: ">=2.15.0"
plugin_routing:
modules:
old_module:
redirect: namespace.collection.new_module
deprecation:
removal_version: "3.0.0"
warning_text: "Use new_module instead"
The Error
Problematic Code
# meta/runtime.yml
---
requires_ansible: ">=2.9"
Lint Output
$ ansible-lint meta/runtime.yml
WARNING Listing 1 violation(s) that are fatal
schema[meta-runtime]: $ None is not of type 'object'.
meta/runtime.yml:1
Rule Violation Summary
count tag profile rule associated tags
1 schema[meta-runtime] basic core
Failed: 1 failure(s), 0 warning(s) on 1 files.
The error occurs because ansible-core 2.9 does not exist (Ansible 2.9 was the monolithic package before the split). The requires_ansible key must reference valid ansible-core versions.
Correct Code
# meta/runtime.yml
---
requires_ansible: ">=2.15.0"
Supported ansible-core Versions
As of 2026, the currently supported versions:
| ansible-core | Status | End of Life |
|---|---|---|
| 2.16.x | Maintained | Nov 2025 |
| 2.17.x | Maintained | May 2026 |
| 2.18.x | Current | Nov 2026 |
| 2.19.x | Current | May 2027 |
| 2.20.x | Latest | Nov 2027 |
End of life (no longer valid for requires_ansible):
| ansible-core | EOL Date |
|---|---|
| 2.13.x | Nov 2023 |
| 2.14.x | May 2024 |
| 2.15.x | Nov 2024 |
If your requires_ansible references an EOL version, ansible-lint will flag it.
Version Constraint Syntax
The requires_ansible field uses PEP 440 version specifiers:
# Minimum version only
requires_ansible: ">=2.15.0"
# Version range
requires_ansible: ">=2.15.0,<2.19.0"
# Compatible release (any 2.17.x)
requires_ansible: "~=2.17.0"
# Exact version (not recommended)
requires_ansible: "==2.17.5"
Recommended Patterns
# ✅ Support current + 2 older maintained versions
requires_ansible: ">=2.16.0"
# ✅ Restrict to tested versions
requires_ansible: ">=2.16.0,<2.21.0"
# ❌ Too old — 2.9 is pre-split, not ansible-core
requires_ansible: ">=2.9"
# ❌ Too restrictive — limits adoption
requires_ansible: "==2.17.3"
Common Causes of the Error
1. Referencing Pre-Split Ansible Versions
# ❌ Ansible 2.9 was monolithic, not ansible-core
requires_ansible: ">=2.9"
# ❌ ansible-base 2.10 was renamed to ansible-core
requires_ansible: ">=2.10"
# ✅ Use ansible-core version numbers (2.14+)
requires_ansible: ">=2.15.0"
2. Missing runtime.yml Entirely
If your collection lacks meta/runtime.yml, ansible-lint may also flag issues when it cannot determine compatibility.
# Create the file
mkdir -p meta
cat > meta/runtime.yml << 'EOF'
---
requires_ansible: ">=2.15.0"
EOF
3. Invalid YAML Structure
# ❌ Wrong — top level must be a mapping
- requires_ansible: ">=2.15.0"
# ✅ Correct
---
requires_ansible: ">=2.15.0"
4. Unsupported Version in Range
# ❌ 2.13 is EOL
requires_ansible: ">=2.13.0"
# ✅ Update to currently supported minimum
requires_ansible: ">=2.16.0"
Plugin Routing in runtime.yml
Beyond requires_ansible, runtime.yml handles module and plugin migrations:
Redirecting Deprecated Modules
---
requires_ansible: ">=2.16.0"
plugin_routing:
modules:
old_module_name:
redirect: my_namespace.my_collection.new_module_name
Deprecating a Module
plugin_routing:
modules:
legacy_module:
deprecation:
removal_version: "4.0.0"
warning_text: "Use 'modern_module' instead. This module will be removed in version 4.0.0."
Removing a Module
plugin_routing:
modules:
removed_module:
tombstone:
removal_version: "3.0.0"
warning_text: "This module has been removed. Use 'replacement_module' instead."
Routing for Different Plugin Types
plugin_routing:
modules:
old_module:
redirect: namespace.collection.new_module
lookup:
old_lookup:
redirect: namespace.collection.new_lookup
filter:
old_filter:
redirect: namespace.collection.new_filter
callback:
old_callback:
redirect: namespace.collection.new_callback
Complete runtime.yml Example
---
requires_ansible: ">=2.16.0"
plugin_routing:
modules:
# Redirect old module name to new
my_old_module:
redirect: my_namespace.my_collection.my_new_module
# Deprecate a module with warning
legacy_config:
deprecation:
removal_version: "3.0.0"
warning_text: >-
Use 'advanced_config' module instead.
This module will be removed in version 3.0.0.
# Module completely removed
ancient_module:
tombstone:
removal_version: "2.0.0"
warning_text: >-
This module was removed in version 2.0.0.
Use 'modern_module' instead.
action:
old_action:
redirect: my_namespace.my_collection.new_action
Updating requires_ansible for New Releases
When a new ansible-core version releases, update your collection's compatibility:
# Check current setting
cat meta/runtime.yml
# Update minimum version
sed -i 's/requires_ansible: ">=2.15.0"/requires_ansible: ">=2.16.0"/' meta/runtime.yml
# Validate
ansible-lint meta/runtime.yml
Testing Against Multiple Versions
Use a CI matrix to test your collection against supported versions:
# .github/workflows/test.yml
strategy:
matrix:
ansible-core:
- "2.16"
- "2.17"
- "2.18"
steps:
- name: Install ansible-core
run: pip install ansible-core~=${{ matrix.ansible-core }}
- name: Run tests
run: ansible-test sanity --docker
Best Practices
- Set
requires_ansibleto the oldest supported version you test against — don't claim compatibility you haven't verified - Update when versions reach EOL — bump the minimum version to stay current
- Use ranges for upper bounds —
>=2.16.0,<2.21.0prevents untested combinations - Include
runtime.ymlin every collection — even if you only setrequires_ansible - Use plugin routing for renames — never break users by removing modules without redirects
- Run
ansible-lintin CI — catch meta-runtime violations before publishing to Galaxy - Follow semantic versioning for your collection — major version bumps when dropping old ansible-core support
Related Articles
Conclusion
The meta-runtime lint rule ensures your collection's requires_ansible key references valid, supported ansible-core versions. The fix is straightforward: update the version constraint to a currently maintained ansible-core release (2.16+). Beyond version constraints, use plugin_routing in runtime.yml to handle module renames, deprecations, and removals gracefully.