guest@6admin.io:~$

When a Chocolatey checksum breaks a whole provisioning run

The provisioning of a fleet of Windows machines stops dead on an Ansible task installing a Chocolatey package and the message is a classic of the genre:

ERROR: Checksum for 'p4vinst64.exe' did not meet '45648d...852bd5'
for checksum type 'sha256'.

The checksum the package expects does not match the downloaded binary. Nothing in my infrastructure changed and yet the day before it worked. The story is short, but it says something important about what “depending on a community package” really means.

What happened

The Chocolatey Community p4v package does not embed the binary, it points at the vendor’s download server and verifies a checksum. Perforce published a new build of p4vinst64.exe on its server without the package maintainer updating the corresponding checksum. As a result the binary’s real hash no longer matches the one frozen in the package, Chocolatey refuses the install and Ansible fails.

This is the correct behaviour and it bears underlining: the checksum verification did exactly its job, it refused a binary whose fingerprint did not match the expected one. The problem is not the control, it is the desynchronisation between two parties I control neither of, the vendor pushing the binary and the volunteer maintainer updating the package. And that desynchronisation is common for packages whose binary is hosted at the vendor rather than embedded in the package.

The three ways out and what they cost

The first is to wait: report it to the maintainer and wait for a republish. It is clean, it touches nothing on my side and it is useless when a provisioning run is blocked, because the delay is measured in hours or days.

The second is to pass ignore_checksums and this is where you have to be disciplined. Enabled globally on the install loop, that flag disables verification for every package, not just the one that is stuck, which amounts to pulling the smoke detector because a pan burned. The right spelling conditions it to the one offending package:

- name: Install packages
  chocolatey.chocolatey.win_chocolatey:
    name: "{{ item.name | default(item) }}"
    state: present
    ignore_checksums: "{{ item.ignore_checksums | default(false) }}"
  loop: "{{ packages }}"
packages:
  - git
  - vscode
  - name: p4v
    ignore_checksums: true

It is an unblock, owned as such, to be removed the moment the upstream package is fixed and never a permanent default.

The third is the real underlying answer: host your own NuGet packages, with the binary embedded in the package rather than downloaded from the vendor. You gain control of versions and checksums, independence from the community and above all reproducibility, a deployment that gives the same result today and in six months. You lose the setup effort and the ongoing maintenance, watching upstream releases and rebuilding, but for a fleet’s critical tools, the ones that regularly throw this kind of glitch, that is the price of reproducibility.

One byte, the whole provisioning down

A checksum that refuses a binary is not an outage, it is a control working and the global --ignore-checksums reflex is exactly the wrong answer because it turns a one-off incident into a permanent blind spot. Depending on a package whose binary lives at the vendor is accepting two points of failure you do not control and for a provisioning you want reproducible, hosting critical packages internally is not over-engineering, it is the condition for “the same playbook” to mean “the same result”. Short term, the conditional bypass on the one offending package; medium term, the internal NuGet repository for the tools that matter.