Pesan Error dan Maknanya
Ketika kamu menjalankan instalasi paket Python menggunakan file requirements dengan flag --require-hashes, pip dapat memunculkan pesan error yang kurang lebih seperti berikut:
ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. If you wish to install without verifying hashes, remove the --require-hashes flag from the pip command.
expected sha256 abc123def456...
got sha256 789ghi012jkl345...
Pesan di atas merupakan mekanisme keamanan bawaan pip yang memverifikasi integritas setiap paket yang diunduh. Flag --require-hashes memaksa pip untuk mencocokkan nilai hash (umumnya algoritma SHA-256) yang tercantum di file requirements dengan nilai hash file yang benar-benar diunduh dari server PyPI. Ketika terjadi ketidakcocokan, pip langsung menghentikan proses instalasi dan menolak paket tersebut.
Dalam bahasa Indonesia sederhana, error ini berarti: "Hash (sidik jari digital) paket yang diunduh berbeda dari hash yang tertulis di file requirements, sehingga pip menolak menginstal karena integritas paket tidak terverifikasi."
Error ini muncul karena pip menerapkan prinsip trust on first use yang ketat. Ketika kamu (atau tim kamu) membuat file requirements dengan hash, nilai tersebut merekam keadaan paket pada saat itu. Jika kemudian ada perubahan—baik pada versi paket, kondisi jaringan, maupun cache lokal—maka verifikasi akan gagal. Ini sebenarnya fitur keamanan, bukan bug: pip melindungi kamu dari paket yang telah dimanipulasi (supply chain attack) atau korup saat proses unduhan.
Contoh situasi yang memicu error:
# File requirements.txt berisi:
django==4.2.7 \
--hash=sha256:abc123def456...
# Namun hash yang tercantum sudah outdated
# karena versi 4.2.7 di PyPI sudah di-rebuild
pip install --require-hashes -r requirements.txt
# ERROR: THESE PACKAGES DO NOT MATCH THE HASHES...
Penyebab yang Paling Sering
1. Paket di-rebuild atau di-reupload oleh maintainer di PyPI tanpa perubahan nomor versi.
Ini merupakan penyebab paling sering dan paling membingungkan. Beberapa maintainer paket melakukan re-upload file distribusi (wheel atau sdist) dengan nomor versi yang sama, misalnya karena menemukan bug kecil pada proses build atau metadata. Ketika ini terjadi, file baru memiliki hash berbeda meskipun versi tetap sama. File requirements kamu masih merekam hash lama, sementara pip mengunduh file baru dari PyPI, sehingga terjadi ketidakcocokan.
2. Cache pip menyimpan file versi lama yang hash-nya berbeda dari yang diharapkan.
Pip menyimpan unduhan paket di direktori cache (~/.cache/pip di Linux/macOS, %LocalAppData%\pip\Cache di Windows). Jika sebelumnya kamu pernah mengunduh paket yang sama dengan hash berbeda—misalnya dari index alternatif atau sebelum maintainer melakukan re-upload—maka pip dapat menggunakan file cache tersebut. Verifikasi hash gagal karena cache tidak merefleksikan file terkini di PyPI.
3. File requirements di-generate di environment atau platform berbeda.
Saat kamu membuat hash di Linux tetapi menginstal di Windows, atau sebaliknya, ada kasus di mana paket tertentu menyediakan wheel berbeda per platform. Wheel untuk manylinux dan wheel untuk win_amd64 tentu memiliki hash berbeda. Jika file requirements hanya mencantumkan hash untuk satu platform, instalasi di platform lain akan gagal.
4. Menggunakan mirror atau proxy PyPI yang tidak sepenuhnya sinkron.
Jika organisasi kamu menggunakan mirror internal (seperti devpi, Nexus, atau Artifactory) yang belum selesai menyinkronkan paket terbaru, kamu bisa mendapatkan file lama yang hash-nya tidak cocok dengan yang di file requirements. Sebaliknya, mirror mungkin sudah memiliki versi terbaru sementara file requirements merekam hash versi lama.
5. Interferensi antivirus atau man-in-the-middle yang memodifikasi file unduhan.
Dalam lingkungan korporat, proxy transparan atau antivirus yang melakukan on-the-fly scanning dapat memodifikasi file yang diunduh, mengubah hash-nya. Ini jarang terjadi pada file wheel (karena berformat zip), tetapi lebih mungkin pada sdist (tarball) yang dapat di-repack oleh proxy.
Cara Memastikan Penyebab Mana yang Kamu Alami
Untuk memastikan, hapus cache pip terlebih dahulu lalu coba unduh ulang. Jika error hilang, penyebabnya adalah cache. Jika error tetap muncul, bandingkan hash yang diharapkan dengan hash aktual menggunakan pip hash:
# Hapus cache pip
pip cache purge
# Unduh paket secara manual lalu cek hash-nya
pip download django==4.2.7 -d ./temp_download
pip hash ./temp_download/django-4.2.7-py3-none-any.whl
Jika hash aktual tidak cocok dengan yang di requirements.txt dan berbeda dari yang ada di PyPI, kemungkinan besar maintainer melakukan re-upload. Jika hash cocok dengan PyPI tetapi tidak dengan requirements.txt, berarti file requirements kamu perlu diperbarui.
Solusi Bertahap
Langkah 1: Perbarui Hash di File Requirements
Solusi paling langsung adalah meregenerasi hash yang benar untuk semua paket. Pip menyediakan cara bawaan untuk ini:
pip-compile --generate-hashes requirements.in > requirements.txt
Jika kamu tidak menggunakan pip-tools, kamu bisa menggunakan perintah berikut:
# Untuk satu paket
pip install django==4.2.7 --dry-run --ignore-installed \
--report - 2>/dev/null | python -c "
import sys, json
report = json.load(sys.stdin)
for item in report['install']:
print(f\"{item['metadata']['name']}=={item['metadata']['version']} \\\\\")
for h in item.get('archive_info', {}).get('hash', {}).items():
print(f\" --hash={h[0]}:{h[1]}\")
"
Namun cara yang lebih praktis dan banyak digunakan adalah menggunakan pip-tools:
# Install pip-tools jika belum ada
pip install pip-tools
# Generate ulang requirements.txt dengan hash
pip-compile --generate-hashes requirements.in
Output yang diharapkan berupa file requirements.txt baru yang berisi hash terkini:
django==4.2.7 \
--hash=sha256:abc123newhash456...
Langkah 2: Bersihkan Cache Pip Sebelum Instalasi Ulang
Meskipun hash sudah diperbarui, cache lama bisa tetap menimbulkan masalah:
# Bersihkan seluruh cache pip
pip cache purge
# Atau hapus hanya cache paket tertentu
pip cache remove django
# Lalu instal ulang
pip install --require-hashes -r requirements.txt
Output yang diharapkan:
Successfully installed django-4.2.7 ...
Langkah 3: Verifikasi Solusi Berhasil
Setelah instalasi selesai tanpa error, verifikasi dengan beberapa cara:
# Pastikan paket terinstal dengan versi yang benar
pip show django
# Output: Name: django, Version: 4.2.7, ...
# Verifikasi hash paket yang terinstal cocok
pip check
# Output: No broken requirements found.
# Jalankan smoke test
python -c "import django; print(django.get_version())"
# Output: 4.2.7
Langkah 4: Solusi untuk Kasus Darurat (Sementara)
Jika kamu sedang dalam situasi darurat dan harus menginstal segera, kamu bisa menghilangkan flag --require-hashes, tetapi ini mengorbankan keamanan verifikasi integritas:
# HAPUS --require-hashes dan hapus semua baris --hash dari requirements.txt
pip install -r requirements.txt
Atau gunakan --no-deps untuk menginstal paket utama saja tanpa dependensi jika masalah hanya pada hash dependensi:
pip install --require-hashes --no-deps -r requirements.txt
Peringatan: Pendekatan ini hanya boleh digunakan sebagai penanganan sementara. Tanpa verifikasi hash, kamu rentan terhadap supply chain attack di mana paket berbahaya bisa menyamar sebagai paket legit.
Langkah 5: Fix untuk Root Cause Re-upload oleh Maintainer
Jika penyebabnya adalah re-upload, file requirements harus merekam hash dari semua distribusi yang tersedia (wheel untuk berbagai platform dan sdist):
# Generate hash untuk semua distribusi (cross-platform)
pip-compile --generate-hashes \
--all-extras \
requirements.in > requirements.txt
Atau secara manual dengan pip download:
# Unduh semua varian distribusi
pip download --no-deps django==4.2.7 -d ./temp
# Hitung hash masing-masing
for f in ./temp/*; do
echo "$(basename $f): $(pip hash $f | grep -oP 'sha256:\w+')"
done
# Output:
# django-4.2.7-py3-none-any.whl: sha256:abc123...
# Django-4.2.7.tar.gz: sha256:def456...
Kemudian masukkan semua hash tersebut ke requirements.txt agar kompatibel lintas platform.
Supaya Tidak Terulang
Konfigurasi yang Mencegah Error Kembali
Solusi permanen melibatkan otomasi dan disiplin workflow. Pertama, jangan pernah mengedit hash di requirements.txt secara manual. Selalu gunakan tool untuk meng-generate. Kedua, integrasikan regenerasi hash ke dalam CI/CD pipeline:
# Contoh GitHub Actions workflow
name: Update Requirements Hashes
on:
schedule:
- cron: '0 6 * * 1' # Setiap Senin pagi
workflow_dispatch: # Bisa di-trigger manual
jobs:
update-hashes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install pip-tools
- run: pip-compile --generate-hashes requirements.in
- name: Create PR if changed
uses: peter-evans/create-pull-request@v6
with:
title: "chore: update requirements hashes"
commit-message: "auto-update hashes"
Workflow di atas secara periodik memeriksa dan memperbarui hash, membuat pull request jika ada perubahan. Ini memastikan file requirements selalu memiliki hash yang valid.
Best Practice untuk Workflow dengan Hash
Pertama, pisahkan spesifikasi dependensi logis (requirements.in) dari file yang dikunci (requirements.txt). File .in berisi deklarasi dependensi tanpa hash, sementara file .txt berisi versi yang dikunci beserta hash. Kedua, selalu commit file requirements.in dan requirements.txt bersamaan ke version control. Ketiga, tambahkan hook pre-commit yang memvalidasi hash sebelum push:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: verify-hashes
name: Verify requirements hashes
entry: bash -c "pip-compile --generate-hashes requirements.in --output-file - | diff - requirements.txt"
language: system
pass_filenames: false
Keempat, untuk proyek lintas platform, selalu sertakan hash untuk semua varian distribusi (wheel manylinux, win_amd64, macosx, dan sdist):
# Generate hash lengkap untuk cross-platform
pip-compile --generate-hashes \
--no-emit-index-url \
--allow-unsafe \
requirements.in
Perbedaan Berdasarkan OS
Di Linux dan macOS, cache pip berada di ~/.cache/pip/. Untuk membersihkannya secara permanen dari cron: