ansible/ansible · error · ValueError

internal error: required and default are mutually exclusive

Error message

internal error: required and default are mutually exclusive for %s

What it means

Raised by _handle_aliases() in ansible.module_utils.common.parameters with ValueError when an argument_spec entry declares both required=True and a non-None default. These are mutually exclusive because a required parameter must always be supplied by the user, so a default can never apply. The 'internal error' prefix signals a bug in the module's own spec, not user input.

Source

Thrown at lib/ansible/module_utils/common/parameters.py:232

    :param alias_deprecations:
    :type alias_deprecations: list
    """

    aliases_results = {}  # alias:canon

    for (k, v) in argument_spec.items():
        aliases = v.get('aliases', None)
        default = v.get('default', None)
        required = v.get('required', False)

        if alias_deprecations is not None:
            for alias in argument_spec[k].get('deprecated_aliases', []):
                if alias.get('name') in parameters:
                    alias_deprecations.append(alias)

        if default is not None and required:
            # not alias specific but this is a good place to check this
            raise ValueError("internal error: required and default are mutually exclusive for %s" % k)

        if aliases is None:
            continue

        if not is_iterable(aliases) or isinstance(aliases, (bytes, str)):
            raise TypeError('internal error: aliases must be a list or tuple')

        for alias in aliases:
            aliases_results[alias] = k
            if alias in parameters:
                if k in parameters and alias_warnings is not None:
                    alias_warnings.append((k, alias))
                parameters[k] = parameters[alias]

    return aliases_results


def _list_deprecations(argument_spec, parameters, prefix=''):

View on GitHub (pinned to 9cf16a4aca)

Solutions

  1. Decide the semantics: if the value is truly required, remove the default
  2. If a sensible fallback exists, remove required: true and keep the default
  3. Add a unit test that instantiates the module (or validates the spec) so spec errors fail in CI, not on the target host

Example fix

# before
argument_spec = dict(
    path=dict(type='str', required=True, default='/tmp'),
)

# after
argument_spec = dict(
    path=dict(type='str', default='/tmp'),
)
Defensive patterns

Strategy: validation

Validate before calling

for name, spec in argument_spec.items():
    if spec.get('required') and spec.get('default') is not None:
        raise AssertionError(f'{name}: required and default are mutually exclusive')

Prevention

When it happens

Trigger: Defining argument_spec = {'name': {'required': True, 'default': 'x'}} and instantiating AnsibleModule. Note the check uses `default is not None`, so default=None with required=True is allowed.

Common situations: Module authors adding a default for convenience after previously marking a param required; copy-paste of spec entries; third-party or collection modules with untested spec combinations.

Related errors


AI-assisted analysis of ansible/ansible@9cf16a4aca (2026-08-15). Data as JSON: /api/errors/0577a84b171899f4. Report an issue: GitHub.