# Ansible shows error on wrong place

**URL:** <https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461>\
**Category:** Get Help\
**Tags:** error, ansible-project, ubuntu\
**Created:** [March 1, 2026, 7:03am UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461 "2026-03-01T07:03:34Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![dietrich](https://avatars.discourse-cdn.com/v4/letter/d/439d5e/32.png) [@dietrich](https://forum.ansible.com/u/dietrich)\
**Post date:** [March 1, 2026, 7:03am UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/1 "2026-03-01T07:03:34Z")

</div>

Hi,  
I´m just starting with ansible and finishing my first playbook. It´s about downloading released packages from private Github Repositories. They can be either whl packages or packed tar.gz. Therefore I implemented different tasks for each case. The results seem to be ok, the file is downloaded and extracted properly. But there is a very confusing error message appearing when downloading a .whl file, if downloading a tar.gz file, there is no error message.

Here´s the code:

```auto
    - name: Extract tar.gz file
      ansible.builtin.unarchive:
        src: "{{ dowloaded_file.dest }}"
        dest: "{{ package_dir }}"
      register: file_to_copy
      when: dowloaded_file.dest.endswith('.tar.gz')
    
    - name: Set file_to_copy if whl package
      ansible.builtin.set_fact:
        file_to_copy: "{{ dowloaded_file.dest }}"
      when: dowloaded_file.dest.endswith('.whl')

    - name: Print filename 2
      ansible.builtin.debug:
        msg: "After unpacking: {{ file_to_copy }}"

    - name: Copy whl file
      ansible.builtin.copy:
        src: "{{ file_to_copy }}"
        dest: "{{ package_dir }}"
        mode: "0755"
      #register: files

    # there are multiple branches needed, depending on the file type
    - name: Print filename
      ansible.builtin.debug:
        msg: "Finished: {{ file_to_copy }}"

```

The error message is this:

```auto
TASK [Copy whl file] ***************************************************************************************
[ERROR]: Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'
Origin: /home/dw/code/openocd-tcl-controller/repo_config/ansible/download_release.yml:80:7

78 msg: "After unpacking: {{ file_to_copy }}"
79
80 - name: Copy whl file
         ^ column 7

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'"}

PLAY RECAP *************************************************************************************************
localhost : ok=11 changed=0 unreachable=0   

```

Whats confusing is: the Task “Copy whl file” does not have any endswith functionality used from my point of view.  
Can someone explain what is going on there? Even if it´s working out, I don´t like to have this error there and want to fix it.

BR  
Dietrich

---

<div class="post-metadata">

**Author:** ![mariolenz](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mariolenz/32/108_2.png) [@mariolenz](https://forum.ansible.com/u/mariolenz)\
**Post date:** [March 1, 2026, 12:05pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/2 "2026-03-01T12:05:05Z")

</div>

First things first, please mention the ansible-core version you’re using. I think there have been quite some changes to 2.19, so it might be worth knowing what exact version you’re running.

That said, you’re using `file_to_copy` both as a host fact (in `Set file_to_copy if whl package`) and as a variable within the play (`register: file_to_copy`). I’m not sure if they are really the same, so maybe Ansible gets confused by this. Just an idea.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [March 1, 2026, 1:48pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/3 "2026-03-01T13:48:17Z")

</div>

A way to reproduce this (I used ansible-core devel, but likely everything \>= 2.19 will work):

```yaml
- hosts: localhost
  gather_facts: false
  vars:
    dowloaded_file:
      dest: foo.tar.gz
    package_dir: /tmp
    file_to_copy: /tmp/asdf
  tasks:
    - name: Extract tar.gz file
      debug:
        msg: "foo"
      register: file_to_copy
      when: dowloaded_file.dest.endswith('.tar.gz')

    - name: Set file_to_copy if whl package
      ansible.builtin.set_fact:
        file_to_copy: "{{ dowloaded_file.dest }}"
      when: dowloaded_file.dest.endswith('.whl')

    - name: Print filename 2
      ansible.builtin.debug:
        msg: "After unpacking: {{ file_to_copy }}"

    - name: Copy whl file
      ansible.builtin.copy:
        src: "{{ file_to_copy }}"
        dest: "{{ package_dir }}"
        mode: "0755"

```

The problem is that `file_to_copy` is a dictionary here (thanks to the “Extract tar.gz file” task) and not a string, and the exact error in the “Copy whl file” task is only visible when enabling tracebacks (for example by setting the environment variable `ANSIBLE_DISPLAY_TRACEBACK=error`):

```auto
TASK [Copy whl file] *******************************************************************************************************************************************************
[ERROR]: Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'
Origin: /path/to/test-error.yml:24:7

22 msg: "After unpacking: {{ file_to_copy }}"
23
24 - name: Copy whl file
         ^ column 7

Traceback (most recent call last):
  File "/path/to/ansible/executor/task_executor.py", line 423, in _execute
    result = self._execute_internal(templar, variables)
  File "/path/to/ansible/executor/task_executor.py", line 636, in _execute_internal
    result = self._handler.run(task_vars=vars_copy)
  File "/path/to/ansible/plugins/action/copy.py", line 469, in run
    trailing_slash = source.endswith(os.path.sep)
                     ^^^^^^^^^^^^^^^
AttributeError: '_AnsibleTaggedDict' object has no attribute 'endswith'

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

Traceback (most recent call last):
  File "/path/to/ansible/executor/task_executor.py", line 428, in _execute
    raise AnsibleTaskError(obj=self._task.get_ds()) from ex
ansible.errors.AnsibleTaskError: Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: '_AnsibleTaggedDict' object has no attribute 'endswith'"}

```

The error happens in the `copy` task, but it’s a crash in the action plugin. It’s basically a bug in the parameter validation of the `copy` action. (Actually it’s the **missing** error validation of the `copy` action.)

(This bug is triggered by a bug in the playbook, see what @mariolenz wrote.)

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [March 1, 2026, 2:51pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/4 "2026-03-01T14:51:52Z")

</div>

> <https://github.com/ansible/ansible/issues/86607>
>
> \### Summary
> 
> Reproducer:
> \`\`\`yaml
> \- hosts: localhost
> gather\_facts: false
> task…s:
> - ansible.builtin.copy:
> src:
> foo: bar
> dest: /tmp/
> mode: "0755"
> \`\`\`
> This produces an error:
> \`\`\`
> TASK \[ansible.builtin.copy\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
> \[ERROR\]: Task failed: '\_AnsibleTaggedDict' object has no attribute 'endswith'
> Origin: playbook.yml:4:7
> 
> 2 gather\_facts: false
> 3 tasks:
> 4 - ansible.builtin.copy:
> ^ column 7
> 
> fatal: \[localhost\]: FAILED! =\> {"changed": false, "msg": "Task failed: '\_AnsibleTaggedDict' object has no attribute 'endswith'"}
> \`\`\`
> This error message unfortunately hides the actual error, which can be seen when setting \`ANSIBLE\_DISPLAY\_TRACEBACK=error\`:
> \`\`\`
> TASK \[ansible.builtin.copy\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
> \[ERROR\]: Task failed: '\_AnsibleTaggedDict' object has no attribute 'endswith'
> Origin: playbook.yml:4:7
> 
> 2 gather\_facts: false
> 3 tasks:
> 4 - ansible.builtin.copy:
> ^ column 7
> 
> Traceback (most recent call last):
> File "/path/to/ansible/executor/task\_executor.py", line 423, in \_execute
> result = self.\_execute\_internal(templar, variables)
> File "/path/to/ansible/executor/task\_executor.py", line 636, in \_execute\_internal
> result = self.\_handler.run(task\_vars=vars\_copy)
> File "/path/to/ansible/plugins/action/copy.py", line 469, in run
> trailing\_slash = source.endswith(os.path.sep)
> ^^^^^^^^^^^^^^^
> AttributeError: '\_AnsibleTaggedDict' object has no attribute 'endswith'
> 
> The above exception was the direct cause of the following exception:
> 
> Traceback (most recent call last):
> File "/path/to/ansible/executor/task\_executor.py", line 428, in \_execute
> raise AnsibleTaskError(obj=self.\_task.get\_ds()) from ex
> ansible.errors.AnsibleTaskError: Task failed: '\_AnsibleTaggedDict' object has no attribute 'endswith'
> 
> fatal: \[localhost\]: FAILED! =\> {"changed": false, "msg": "Task failed: '\_AnsibleTaggedDict' object has no attribute 'endswith'"}
> \`\`\`
> 
> \### Issue Type
> 
> Bug Report
> 
> \### Component Name
> 
> copy
> 
> \### Ansible Version
> 
> \`\`\`console
> stable-2.19
> stable-2.20
> devel
> \`\`\`
> 
> \### Configuration
> 
> \`\`\`console
> /
> \`\`\`
> 
> \### OS / Environment
> 
> /
> 
> \### Steps to Reproduce
> 
> See above
> 
> \### Expected Results
> 
> Either action fails because the dict-to-string converted source doesn't exist, or it fails because the input isn't a string (would be bad in case of integers which match filenames that exist).
> 
> \### Actual Results
> 
> \`\`\`console
> See above.
> \`\`\`
> 
> \### Code of Conduct
> 
> \- \[x\] I agree to follow the Ansible Code of Conduct

---

<div class="post-metadata">

**Author:** ![dietrich](https://avatars.discourse-cdn.com/v4/letter/d/439d5e/32.png) [@dietrich](https://forum.ansible.com/u/dietrich)\
**Post date:** [March 1, 2026, 10:02pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/5 "2026-03-01T22:02:05Z")

</div>

> [@mariolenz](#):
>
> First things first, please mention the ansible-core version you’re using. I think there have been quite some changes to 2.19, so it might be worth knowing what exact version you’re running.
> 
> That said, you’re using `file_to_copy` both as a host fact (in `Set file_to_copy if whl package`) and as a variable within the play (`register: file_to_copy`). I’m not sure if they are really the same, so maybe Ansible gets confused by this. Just an idea.

Version is  
ansible [core 2.20.3]  
installed with pip and running on Ubuntu WSL2 distribution.

I understood your second point. I assumed here that the same variable will be set with this approach, no matter which task is executed. Would something like pulling file\_to\_copy to the beginning of the play be more ansible-compliant?

---

<div class="post-metadata">

**Author:** ![dietrich](https://avatars.discourse-cdn.com/v4/letter/d/439d5e/32.png) [@dietrich](https://forum.ansible.com/u/dietrich)\
**Post date:** [March 1, 2026, 10:06pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/6 "2026-03-01T22:06:34Z")

</div>

Impressive.

Can I do something as a workaround, until it is fixed and released?

---

<div class="post-metadata">

**Author:** ![flowerysong](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/flowerysong/32/2305_2.png) [@flowerysong](https://forum.ansible.com/u/flowerysong)\
**Post date:** [March 1, 2026, 10:36pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/7 "2026-03-01T22:36:14Z")

</div>

> [@dietrich](#):
>
> Can I do something as a workaround, until it is fixed and released?

Pass a valid path instead of an invalid one.

---

<div class="post-metadata">

**Author:** ![dietrich](https://avatars.discourse-cdn.com/v4/letter/d/439d5e/32.png) [@dietrich](https://forum.ansible.com/u/dietrich)\
**Post date:** [March 2, 2026, 5:37am UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/8 "2026-03-02T05:37:33Z")

</div>

What do you mean?  
The paths are valid, files are downloaded and extracted as expected. Just the message is confusing.

---

<div class="post-metadata">

**Author:** ![mariolenz](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mariolenz/32/108_2.png) [@mariolenz](https://forum.ansible.com/u/mariolenz)\
**Post date:** [March 2, 2026, 6:01pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/9 "2026-03-02T18:01:16Z")

</div>

@flowerysong If you really want to be helpful, you probably shouldn’t just say ~~pass a valid path instead of an invalid one~~ you’re holding it wrong 😏

---

<div class="post-metadata">

**Author:** ![jborean](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jborean/32/1525_2.png) [@jborean](https://forum.ansible.com/u/jborean)\
**Post date:** [March 2, 2026, 6:56pm UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/10 "2026-03-02T18:56:55Z")

</div>

> [@dietrich](#):
>
> The paths are valid, files are downloaded and extracted as expected. Just the message is confusing.

You have

```yaml
src: "{{ file_to_copy }}"

```

But you are registering `file_to_copy` as a task result

```yaml
register: file_to_copy

```

You can’t pass in a dictionary value, select the key inside that dictionary that represents your path or use another variable that has your path.

---

<div class="post-metadata">

**Author:** ![dietrich](https://avatars.discourse-cdn.com/v4/letter/d/439d5e/32.png) [@dietrich](https://forum.ansible.com/u/dietrich)\
**Post date:** [March 4, 2026, 6:49am UTC](https://forum.ansible.com/t/ansible-shows-error-on-wrong-place/45461/11 "2026-03-04T06:49:24Z")

</div>

I think I got it. This one causes no errors:

```auto
    - name: Extract tar.gz file
      ansible.builtin.unarchive:
        src: "{{ dowloaded_file.dest }}"
        dest: "{{ package_dir }}"
      register: file_to_copy
      when: dowloaded_file.dest.endswith('.tar.gz')

...

    - name: Set file_to_copy if whl package
      ansible.builtin.set_fact:
        file_to_copy: "{{ dowloaded_file }}"
      when: dowloaded_file.dest.endswith('.whl')
...

    - name: Copy whl file
      ansible.builtin.copy:
        src: "{{ file_to_copy.dest }}"
        dest: "{{ package_dir }}"
        mode: "0755"

```

Is it better? I would still like to have this additional step if tar.gz is downloaded, so in the last step it does not make a difference whether tar.gz or whl is downloaded. Do you have any suggestions to improve here?
