# get\_url makes downloaded file size 0 on second run

**URL:** <https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691>\
**Category:** Get Help\
**Tags:** ansible-core\
**Created:** [October 15, 2025, 7:41pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691 "2025-10-15T19:41:20Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 15, 2025, 7:41pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/1 "2025-10-15T19:41:20Z")

</div>

**get\_url zero’s the file on second run**.

- I run a playbook which downloads and runs a command file.
- get\_url works perfectly 1st time
- I run the same playbook a second time and the downloaded file now has 0 size

ansible version info:  
`ansible [core 2.14.18] config file = /root/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.9/site-packages/ansible ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections executable location = /usr/bin/ansible python version = 3.9.21 (main, Jun 27 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/usr/bin/python3) jinja version = 3.1.2 libyaml = True`

- my code!

```auto
---
# tasks file for agent_1_liner
# MAYBE BUG HERE - on second run file is 0 size
  - name: Download Instana Agent installer
    get_url:
      url: "https://setup.instana.io/agent"
      dest: "/tmp/setup_agent.sh"
      mode: '0700'

  - name: Install Instana Agent
    command:
      cmd: >
        ./setup_agent.sh
        -a "{{ instana_agent_key }}"
        -d "{{ instana_agent_endpoint_key }}"
        -t dynamic
        -e "{{ instana_agent_endpoint }}"
        -y
    become: true
    args:
      chdir: /tmp
      creates: /opt/instana/agent

  - name: Ensure Instana Agent is started and enabled
    systemd:
      name: instana-agent
      state: started
      enabled: true
    become: true

```

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [October 22, 2025, 9:00pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/2 "2025-10-22T21:00:18Z")

</div>

This looks like a bug, possibly related to [ansible 2.8.6 get\_url repeatedly downloads file with force==no · Issue #64016 · ansible/ansible · GitHub](https://github.com/ansible/ansible/issues/64016).

I think you can work around the issue by providing the checksum, for example

```yaml
  - name: Download Instana Agent installer
    get_url:
      checksum: "md5:27da42869c3dcc33897601305ffaf3ab"
      url: "https://setup.instana.io/agent"
      dest: "/tmp/setup_agent.sh"
      mode: '0700'

```

---

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 23, 2025, 10:08am UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/3 "2025-10-23T10:08:05Z")

</div>

Shertel.  
Thanks that works. It does add a maintenance overhead as it will stop working every time the file changes. But as a workaround until the bug is fixed thats great. Thanks.

---

<div class="post-metadata">

**Author:** ![ildjarn](https://avatars.discourse-cdn.com/v4/letter/i/8491ac/32.png) [@ildjarn](https://forum.ansible.com/u/ildjarn)\
**Post date:** [October 23, 2025, 12:57pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/4 "2025-10-23T12:57:34Z")

</div>

Ansbile core 2.14? That has been EOL for quite some time, I think.

Just make sure that the file is not present before downloading.

```yaml
- name: Remove file if it already exists
  ansible.builtin.file:
    path: /tmp/setup_agent.sh
    state: absent

```

---

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 23, 2025, 2:16pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/5 "2025-10-23T14:16:06Z")

</div>

Ildjarn,

Hi. I thought of that but it’s a big file and I don’t want to be downloading it if I have already got it.  
Thanks

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [October 23, 2025, 3:08pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/6 "2025-10-23T15:08:47Z")

</div>

I hesitate (though not enough apparently) to share this task because it’s really a shell script with Ansible window dressing. It’s customized to download a particular file which is in fact a tarball containing an executable which it then installs. But it could be parameterized if you wanted it more generic, and you can strip out the specific untar-and-install bits if you don’t need that. I would have done it, but I’m not going to test it after such changes, and I’d rather post working code than code with untested, broken changes.

The idea is, it uses `curl` to get the headers of the remote file, compares its size and date to the existing file’s size and mtime, and if they aren’t the same it downloads the actual file (and installs it).

We run this step once a day in each of four environments, and it’s been working for years. If you can use it, great. If not, well at least you’ve seen another approach. You get what you paid for. 🙂

```yaml
# BEGIN oc
- name: Download and install oc to /usr/local/bin
  register: install_oc
  changed_when: '"OC_COMMAND_CHANGED" in install_oc.stderr'
  args:
    executable: /bin/bash
  vars:
    oc_by_os:
      '9': "https://{{ local_mirror_for_rhel_9 }}/amd64/linux/oc.tar"
      '8': "https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-linux-amd64-rhel8.tar.gz"
  tags:
    - oc
  ansible.builtin.shell: |
    # Download the latest oc tarball
    set -o pipefail

    # The Big Hammer. Only uncomment if you want to start testing from scratch.
    # rm -f /usr/local/bin/oc.tar

    tarhome=/usr/local/bin
    tarfile="{{ oc_by_os[ansible_distribution_major_version] | regex_replace('^.*/(.*)', '\1') }}"
    member=oc
    declare -A urls=(
      [upstream]="{{ oc_by_os[ansible_distribution_major_version] }}"
      [downstream]="file://${tarhome}/${tarfile}"
    )

    scratch=$(mktemp -d -t tmp.XXXXXXXXXX)

    function finish {
      rm -rf "$scratch"
      echo # Need a blank line in the emailed reports.
    }
    trap finish EXIT

    function url_statter() {
       declare -n ref="$1"
       declare -g -A "$1"
       declare url="$2"
       local key value
       while read -r -d $'\r' key value; do
          if [[${key} =~ ^([a-zA-Z0-9_-]+): ]] ; then
             # Note: the ",," down-cases all the keys, so
             # compare "content-length", not "Content-Length" for example.
             # shellcheck disable=SC2034
             ref["${BASH_REMATCH[1],,}"]="${value}"
          fi
       done < <( curl -s -L -I "$url" )
    }

    function statter_eq() {
       declare -n statter_l="$1"
       declare -n statter_r="$2"
       if ["${statter_l[content-length]:-l0}" = "${statter_r[content-length]:-r0}" ] && \
          ["${statter_l[last-modified]:-l0}" = "${statter_r[last-modified]:-r0}" ] ; then
          return 0
       else
          return 1
       fi
    }
    url_statter upstream "${urls[upstream]}"
    url_statter downstream "${urls[downstream]}"

    echo " ***Comparing upstream and downstream urls***"
    echo " upstream url: ${urls[upstream]}"
    echo " downstream url: ${urls[downstream]}"
    echo
    echo " upstream: ${upstream[content-length]-0} bytes, ${upstream[last-modified]-never}"
    echo "downstream: ${downstream[content-length]-0} bytes, ${downstream[last-modified]-never}"

    if statter_eq upstream downstream ; then
       echo "Downstream is up-to-date with upstream."
       exit 0
    else
       echo "Downloading upstream URL to downstream."
    fi

    if [-f "${tarhome}/${tarfile}"] ; then
       cp "${tarhome}/${tarfile}" "${scratch}/${tarfile}"
       touch -r "${tarhome}/${tarfile}" "${scratch}/${tarfile}"
    fi

    url_statter before "file://${tarhome}/${tarfile}"

    # This test is a convenient way to switch between `wget` and `curl` as the download tool of choice.
    if true ; then
       if ! wget -N -S -P "${scratch}" --no-if-modified-since "${urls[upstream]}" 2> "${scratch}/wget.log" ; then
          echo "wget failed; exiting"
          grep -v 'K ..........' "${scratch}/wget.log"
          exit 2
       fi
       grep -v 'K ..........' "${scratch}/wget.log"
    else
       if ! curl --remote-time -o "${scratch}/${tarfile}" --dump-header "${scratch}/curl-headers" "${urls[upstream]}" 2> "${scratch}/curl.log" ; then
          echo "curl failed; exiting"
          cat "${scratch}/curl.log"
          exit 2
       fi
       cat "${scratch}/curl.log"
       cat "${scratch}/curl-headers"
    fi

    url_statter after "file://${scratch}/${tarfile}"

    echo "before: ${before[content-length]-0} bytes, ${before[last-modified]-never}"
    echo " after: ${after[content-length]-0} bytes, ${after[last-modified]-never}"

    if statter_eq before after ; then
       echo "after is up-to-date with before."
       exit 0
    else
       echo "Updated ${tarfile} downloaded to ${scratch}."
       tar --extract -f "${scratch}/${tarfile}" -C "${scratch}" "${member}"
       ls -l --full-time "${scratch}/${tarfile}" "${scratch}/${member}" "${tarhome}/${tarfile}" "${tarhome}/${member}"
       cp -p "${scratch}/${tarfile}" "${tarhome}/${tarfile}"
       cp -p "${scratch}/${member}" "${tarhome}/${member}"
       ls -l --full-time "${scratch}/${tarfile}" "${scratch}/${member}" "${tarhome}/${tarfile}" "${tarhome}/${member}"
       echo "OC_COMMAND_CHANGED" >&2
    fi
# END oc

```

---

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 23, 2025, 5:46pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/7 "2025-10-23T17:46:44Z")

</div>

Todd, Thanks for that.  
Strangely If I pull the headers for the file I don’t get modification date or file size. I tried it with curl and with python requests.  
However, I do get 6 values that might be related to the file release or the upload process. So, hopefully they are unique for different versions. This just means I have to save this info when I download the file and then check it before I download again.  
Now I have to wait for the agent file to be modified before I can test this theory 🙂

I would never have thought to check the headers without your reply. So thanks again

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [October 23, 2025, 6:05pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/8 "2025-10-23T18:05:15Z")

</div>

> [@tivolinick](#):
>
> Now I have to wait for the agent file to be modified before I can test this theory 🙂

☹  
Or you can run it a couple of times now. I get different hex strings every time I pull down the headers. Behold:

```plaintext
utoddl@tango:~$ curl -I https://setup.instana.io/agent
HTTP/2 200 
date: Thu, 23 Oct 2025 18:01:33 GMT
server-timing: intid;desc=2935c5338dc6c81b
traceparent: 00-00000000000000002935c5338dc6c81b-2935c5338dc6c81b-01
tracestate: in=2935c5338dc6c81b;2935c5338dc6c81b
x-instana-l: 1
x-instana-s: 2935c5338dc6c81b
x-instana-t: 2935c5338dc6c81b

utoddl@tango:~$ curl -I https://setup.instana.io/agent
HTTP/2 200 
date: Thu, 23 Oct 2025 18:01:37 GMT
server-timing: intid;desc=6c8c5229ead743a9
traceparent: 00-00000000000000006c8c5229ead743a9-6c8c5229ead743a9-01
tracestate: in=6c8c5229ead743a9;6c8c5229ead743a9
x-instana-l: 1
x-instana-s: 6c8c5229ead743a9
x-instana-t: 6c8c5229ead743a9

```

I’m afraid this technique isn’t going to help in this case. Sorry/

---

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 24, 2025, 2:39pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/9 "2025-10-24T14:39:51Z")

</div>

Oh, that’s annoying. Thanks for checking. Back to the drawing board!

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [October 24, 2025, 3:15pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/10 "2025-10-24T15:15:28Z")

</div>

On the other hand, the current “agent” file is only 36,013 bytes. That’s not an onerous download burden.

---

<div class="post-metadata">

**Author:** ![tivolinick](https://avatars.discourse-cdn.com/v4/letter/t/51bf81/32.png) [@tivolinick](https://forum.ansible.com/u/tivolinick)\
**Post date:** [October 27, 2025, 3:19pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/11 "2025-10-27T15:19:55Z")

</div>

Yes, I think delete and download each time will be the way forward. Thanks

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [October 27, 2025, 9:59pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/12 "2025-10-27T21:59:28Z")

</div>

Maybe so. But do you run the installer every time, even if the downloaded installer hasn’t changed?

Here’s an attempt to be more idempotent, at least for that part. It always downloads the installer, but to a temp file. It compares the downloaded file to the “real” installer, and if they are different, it moves the temp file to the “real” installer location and marks the task `changed: true`. The next task only runs the installer if the download’s task changed.

I was going to let this go, but I had a few minutes and it kept me awake last night, so… 🤷  
I hope this helps.

```yaml
---
# tivolinich_01.yml
- name: Download possibly changed agent script
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Download Instana Agent installer
      register: instana_agent_installer
      changed_when: '"INSTANA AGENT INSTALLED" in instana_agent_installer.stderr'
      args:
        executable: /bin/bash
      vars:
        url: https://setup.instana.io/agent
        dest: "/tmp/setup_agent.sh"
        mode: '0700'
      ansible.builtin.shell: |
        # Download the Instana Agent installer
        set -o pipefail

        # The Big Hammer. Only uncomment if you want to start testing from scratch.
        # rm -f {{ dest }}

        function finish {
          rm -rf "$scratch"
          echo # Need a blank line in the emailed reports.
        }
        trap finish EXIT

        do_install() {
          mv "$scratch" "{{ dest }}"
          chmod "{{ mode }}" "{{ dest }}"
          echo "INSTANA AGENT INSTALLED" >&2
          exit 0
        }

        scratch=$(mktemp -p /tmp -t tmp.XXXXXXXXXX)
        if curl -s -L "{{ url }}" -o "$scratch" ; then
          if [! -f "{{ dest }}"] ; then
            do_install
          elif cmp --silent "$scratch" "{{ dest }}" ; then
            # no change
            exit 0
          else
            do_install
          fi
        else
          echo "curl error $?"
          exit 1
        fi

    - name: Install Instana Agent
      ansible.builtin.command:
        cmd: >
          ./setup_agent.sh
          -a "{{ instana_agent_key }}"
          -d "{{ instana_agent_endpoint_key }}"
          -t dynamic
          -e "{{ instana_agent_endpoint }}"
          -y
      become: true
      args:
        chdir: /tmp
      # Was: "creates: /opt/instana/agent"
      when: instana_agent_installer is changed

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [November 26, 2025, 9:59pm UTC](https://forum.ansible.com/t/get-url-makes-downloaded-file-size-0-on-second-run/44691/13 "2025-11-26T21:59:52Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
