{"id":"9bb46b9086faa44d","repo":"python-poetry/poetry","slug":"could-not-determine-a-hash-for-any-distribution-li","errorCode":null,"errorMessage":"Could not determine a hash for any distribution link of package: \"{data.name}\" version: \"{data.version}\"","messagePattern":"Could not determine a hash for any distribution link of package: \"(.+?)\" version: \"(.+?)\"","errorType":"exception","errorClass":"PackageNotFoundError","httpStatus":null,"severity":"error","filePath":"src/poetry/repositories/http_repository.py","lineNumber":492,"sourceCode":"                self._log(\n                    f\"Failed to determine hash of {link.url}. Skipping file.\",\n                    level=\"warning\",\n                )\n            else:\n                files.append(\n                    {\n                        \"file\": link.filename,\n                        \"hash\": file_hash,\n                        \"url\": link.url_without_fragment,\n                    }\n                )\n                if link.size is not None:\n                    files[-1][\"size\"] = link.size\n                if link.upload_time_isoformat is not None:\n                    files[-1][\"upload_time\"] = link.upload_time_isoformat\n\n        if not files:\n            raise PackageNotFoundError(\n                f'Could not determine a hash for any distribution link of package: \"{data.name}\" version:'\n                f' \"{data.version}\"'\n            )\n\n        data.files = files\n\n        # drop yanked files unless the entire release is yanked\n        info = self._get_info_from_links(links, ignore_yanked=not data.yanked)\n\n        data.summary = info.summary\n        data.requires_dist = info.requires_dist\n        data.requires_python = info.requires_python\n\n        return data.asdict()\n\n    def calculate_sha256(self, link: Link) -> str | None:\n        with self._cached_or_downloaded_file(link) as filepath:\n            hash_name = get_highest_priority_hash_type(link.hashes, link.filename)","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/repositories/http_repository.py#L474-L510","documentation":"Raised after link filtering when none of the candidate files yielded a usable hash (http_repository.py:469-495). Poetry requires a content hash for every file it locks; if a link carries no sha512/sha384/sha256 digest AND the on-the-fly sha256 calculation (calculate_sha256) returns None (e.g. download failed, FIPS-mode restriction, or hash mismatch), the file is skipped and this error fires when no file remains.","triggerScenarios":"repository.package() against an index that lists files without any standard digest, while the fallback download for sha256 computation fails or the recomputed known-hash does not match link.hashes (cache.py calculate_sha256 returning None at the mismatch branch). Also triggered in FIPS-enabled environments where the declared hash algorithm is unavailable.","commonSituations":"A private/legacy repository that does not publish sha256 digests; a corrupted download whose recomputed hash disagrees with the index; FIPS mode disabling md5/sha1 such that the known-hash check fails.","solutions":["Ensure the index publishes sha256 (preferred) or sha384/sha512 digests for every file.","Check network connectivity and re-run — a transient download corruption can make calculate_sha256 return None.","If running under FIPS, configure the index to use sha256 digests instead of md5/sha1.","Verify the file on the index is not corrupt by downloading it manually and comparing its checksum."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Before relying on a release, confirm its files carry a digest\nfor link in repository.find_links_for_package(pkg):\n    if not any(h in link.hashes for h in (\"sha256\", \"sha384\", \"sha512\")):\n        log.warning(\"%s has no standard digest; hash resolution may fail\", link.filename)","typeGuard":null,"tryCatchPattern":"from poetry.repositories.exceptions import PackageNotFoundError\ntry:\n    data = repository.package(name, version)\nexcept PackageNotFoundError as e:\n    if \"Could not determine a hash\" in str(e):\n        log.error(\"index missing digests for %s==%s\", name, version)\n    raise","preventionTips":["Configure private indexes to publish sha256 digests for every file.","Avoid FIPS-disabling md5/sha1-only indexes; prefer sha256.","Validate downloaded files independently when operating on untrusted indexes."],"tags":["repository","hash","security","integrity","fips"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}