The 'skipped_reason' value is deprecated

Does anyone have any suggestions regarding what is happening here, I have this DEPRECATION WARNING:

TASK [php : Check php_ variables using the combined argument spec] ************************************************************************************************************************************************
[WARNING]: Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.
[DEPRECATION WARNING]: The 'skipped_reason' value is deprecated. This feature will be removed from ansible-core version 2.24.
Origin: /home/example/php/tasks/verify.yml:79:29

77       ansible.builtin.validate_argument_spec:
78         argument_spec: "{{ php_combined_argument_spec['argument_specs']['main']['options'] }}"
79         provided_arguments: "{{ phphostvars }}"
                               ^ column 29

Use 'skip_reason' instead.

[DEPRECATION WARNING]: While processing '<<container>>': The 'skipped_reason' value is deprecated. This feature will be removed from ansible-core version 2.24.
Origin: <unknown>

<<container>>

Use 'skip_reason' instead.

ok: [example.org.uk]

The task in question is:

    - name: Check php_ variables using the combined argument spec
      ansible.builtin.validate_argument_spec:
        argument_spec: "{{ php_combined_argument_spec['argument_specs']['main']['options'] }}"
        provided_arguments: "{{ phphostvars }}"

And phphostvars is defined thus:

phpvarnames: "{{ q('varnames', '^php_') | sort }}"
phphostvars: "{{ dict(phpvarnames | list | zip(q('vars', *phpvarnames))) }}"

This didn’t generate a warning in the past, I’m currently using this version of Ansible:

ansible --version | head -n1
ansible [core 2.21.0]

Are you using any callback plugins? My assumption is that you might be using a callback plugin that is consuming the deprecated skipped_reason on the task result.

A quick search indicates selective from community.general may be doing so.

I have the following in ansible.cfg and have now commented callback_result_format = yaml but I still have the same warning:

# Ansible configuration
[defaults]
allow_world_readable_tmpfiles = true
any_errors_fatal = true
# callback_result_format = yaml
# callbacks_enabled = timer, profile_tasks, profile_roles
deprecation_warnings = true
display_skipped_hosts = false
duplicate_dict_key = error
# error_on_undefined_vars = 1
force_color = 0
inject_facts_as_vars = 0
inventory = hosts.yml
nocows = true
pipelining = true
retry_files_enabled = false
roles_path = galaxy/roles
timeout = 60
vault_password_file = .vault.passwd
[colors]
debug = blue
# vim: syntax=dosini

I also have this:

TASK [systemd : Verify the service when it is in the list of existing unit files after appending .service for php7.4-fpm] *****************************************************************************************
ok: [example.org.uk]
[WARNING]: Callback dispatch 'v2_runner_on_skipped' failed for plugin 'default': CallbackModule.v2_runner_on_skipped() takes 2 positional arguments but 4 were given

TASK [systemd : Systemd unit enabled for php7.4-fpm] **************************************************************************************************************************************************************
ok: [example.org.uk]

Which is triggered by one of these two tasks:

        - name: "Verify the service when it is in the list of existing unit files after appending .service for {{ systemd_unit.name }}"
          ansible.builtin.command:
            cmd: "systemd-analyze verify {{ systemd_unit.name }}.service --man=false"
          check_mode: false
          vars:
            systemd_unit_verify: "{{ systemd_unit.name }}.service"
          changed_when: false
          when:
            - systemd_unit.name is not regex('[.]service$')
            - systemd_unit_verify in systemd_unit_files_enabled

        - name: "Verify the service when it is in the list of existing unit files for {{ systemd_unit.name }}"
          ansible.builtin.command:
            cmd: "systemd-analyze verify {{ systemd_unit.name }}"
          check_mode: false
          changed_when: false
          when: systemd_unit.name in systemd_unit_files_enabled

Any other suggestions for debugging this? Thanks!

Finding the deprecation is a little harder, but I suppose we can start with the callback failure you provide above.

If you run with these env vars, you will get a full traceback:

ANSIBLE_DISPLAY_TRACEBACK=error _ANSIBLE_CALLBACK_DISPATCH_ERROR_BEHAVIOR=error 

Note that the 2nd env var, prefixed with _ isn’t a “production” config, it exists in it’s current form for this type of debugging, and can be removed without warning.

Thanks, does this result help?

[ERROR]: Callback dispatch 'v2_runner_on_skipped' failed for plugin 'default': CallbackModule.v2_runner_on_skipped() takes 2 positional arguments but 4 were given

Traceback (most recent call last):
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/executor/task_queue_manager.py", line 516, in send_callback
    method(*new_args, **kwargs)
    ~~~~~~^^^^^^^^^^^^^^^^^^^^^
TypeError: CallbackModule.v2_runner_on_skipped() takes 2 positional arguments but 4 were given

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/cli/__init__.py", line 661, in cli_executor
    exit_code = cli.run()
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/cli/playbook.py", line 152, in run
    results = pbex.run()
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/executor/playbook_executor.py", line 179, in run
    result = self._tqm.run(play=play)
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/executor/task_queue_manager.py", line 403, in run
    play_return = strategy.run(iterator, play_context)
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/plugins/strategy/linear.py", line 170, in run
    results.extend(self._execute_meta(task, play_context, iterator, host))
        ¦       ¦  ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/plugins/strategy/__init__.py", line 1021, in _execute_meta
    self._tqm.send_callback('v2_runner_on_skipped', target_host, task, utr)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/utils/lock.py", line 39, in inner
    return func(*args, **kwargs)
  File "/home/example/.local/pipx/venvs/ansible/lib/python3.13/site-packages/ansible/executor/task_queue_manager.py", line 522, in send_callback
    raise AnsibleCallbackError(f"Callback dispatch {method_name!r} failed for plugin {callback_plugin._load_name!r}.") from ex
ansible.errors.AnsibleCallbackError: Callback dispatch 'v2_runner_on_skipped' failed for plugin 'default': CallbackModule.v2_runner_on_skipped() takes 2 positional arguments but 4 were given

That specific issue has been resolved in Fix broken callback dispatch on skipped meta tasks by nitzmahone · Pull Request #86977 · ansible/ansible · GitHub and will be in the 2.21.1 release.

That specific issue has been resolved in Fix broken callback dispatch on skipped meta tasks by nitzmahone · Pull Request #86977 · ansible/ansible · GitHub and will be in the 2.21.1 release.

I haven’t looked more at the skipped_reason warning yet.

Ok, so on to this. Here is what I believe is happening:

  1. You have a task that is registering a var that starts with php_, quite possibly the php_conf_symlinks_present variable. That task is looping over an empty list. For backwards compat in 2.21, if that happens (looping an empty list), we set a skipped_reason on the task result. skipped_reason is now deprecated, so we mark it as such.
  2. Your phpvarnames is picking up every var name that starts with php_, including all of the registered task vars. (I’m not sure this was your intention)
  3. Serializing the data set that includes the skipped_reason results in the deprecation warning.

The easiest way to avoid this might be to do something like:

phphostvars: "{{ dict(phpvarnames | list | zip(q('vars', *phpvarnames) | reject('skipped'))) }}"

But as above, I question whether it was your intention that phpvarnames should also pick up all registered variables. And that is not as easily solved, at least not within the templating you have. It would likely require changing all of your registered var names to not use the php_ prefix to avoid this issue, while not changing the “public” interface of the role.