ansible/ansible · error · AnsibleParserError

The value of the task `args` keyword is invalid.

Error message

The value of the task `args` keyword is invalid.

What it means

ModuleArgsParser validates the task-level `args` keyword: it must be a mapping, a string that is possibly an all-Jinja template (deferred), or None (deprecated-empty). Any other type — list, int, bool — raises AnsibleParserError 'The value of the task `args` keyword is invalid' with help text requiring a mapping or template resolving to one.

Source

Thrown at lib/ansible/parsing/mod_args.py:174

        # final args are the ones we'll eventually return, so first update
        # them with any additional args specified, which have lower priority
        # than those which may be parsed/normalized next
        final_args = dict()

        if additional_args is not Sentinel:
            if isinstance(additional_args, str) and _jinja_bits.is_possibly_all_template(additional_args):
                final_args['_variable_params'] = additional_args
            elif isinstance(additional_args, dict):
                final_args.update(additional_args)
            elif additional_args is None:
                Display().deprecated(
                    msg="Ignoring empty task `args` keyword.",
                    version="2.23",
                    help_text='A mapping or template which resolves to a mapping is required.',
                    obj=self._task_ds,
                )
            else:
                raise AnsibleParserError(
                    message='The value of the task `args` keyword is invalid.',
                    help_text='A mapping or template which resolves to a mapping is required.',
                    obj=additional_args,
                )

        # how we normalize depends if we figured out what the module name is
        # yet.  If we have already figured it out, it's a 'new style' invocation.
        # otherwise, it's not

        if action is not None:
            args = self._normalize_new_style_args(thing, action, additional_args)
        else:
            (action, args) = self._normalize_old_style_args(thing)

            # this can occasionally happen, simplify
            if args and 'args' in args:
                tmp_args = args.pop('args')
                if isinstance(tmp_args, str):

View on GitHub (pinned to 9cf16a4aca)

Solutions

  1. Make args a proper YAML mapping: args: {src: x, dest: y}
  2. If args must be dynamic, use a single Jinja expression that resolves to a dict: args: "{{ item.args }}"
  3. Remove the args keyword and put parameters directly under the module name

Example fix

# before
- ansible.builtin.copy:
    args:
      - src
      - dest

# after
- ansible.builtin.copy:
    args:
      src: /tmp/a
      dest: /tmp/b
Defensive patterns

Strategy: validation

Validate before calling

# Pre-flight check for dynamically built tasks
def task_args_ok(task: dict) -> bool:
    a = task.get('args', '__missing__')
    return a == '__missing__' or isinstance(a, (str, dict)) or a is None

if not task_args_ok(task):
    raise AnsibleError(f"task 'args' must be a mapping or template, got {type(task['args']).__name__}")

Type guard

def is_valid_args(value) -> bool:
    """task `args` must be a Mapping, all-Jinja string, or None."""
    if value is None or isinstance(value, dict):
        return True
    if isinstance(value, str) and '{{' in value and '}}' in value:
        return True
    return False

Prevention

When it happens

Trigger: A task like `- copy: ...` plus `args: [src, dest]` (list), or `args: 42`; a Jinja expression resolving to a non-mapping string that is not recognized as fully templated.

Common situations: YAML indentation errors turning the args mapping into a string/scalar; copy-pasting k=v strings into args; migrating old shorthand args into the args keyword incorrectly.

Related errors


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