{"record":{"id":"867ef34025f41698","repo":"pypa/pip","slug":"invalid-wheel-filename-wheel-filename-r","errorCode":null,"errorMessage":"Invalid wheel filename {wheel.filename!r}","messagePattern":"Invalid wheel filename (.+?)","errorType":"validation","errorClass":"PylockValidationError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/pylock.py","lineNumber":617,"sourceCode":"        )\n        distributions = bool(package.sdist) + len(package.wheels or [])\n        direct_urls = (\n            bool(package.vcs) + bool(package.directory) + bool(package.archive)\n        )\n        if distributions > 0 and direct_urls > 0:\n            raise PylockValidationError(\n                \"None of vcs, directory, archive must be set if sdist or wheels are set\"\n            )\n        if distributions == 0 and direct_urls != 1:\n            raise PylockValidationError(\n                \"Exactly one of vcs, directory, archive must be set \"\n                \"if sdist and wheels are not set\"\n            )\n        for i, wheel in enumerate(package.wheels or []):\n            try:\n                (name, version, _, _) = parse_wheel_filename(wheel.filename)\n            except Exception as e:\n                raise PylockValidationError(\n                    f\"Invalid wheel filename {wheel.filename!r}\",\n                    context=f\"wheels[{i}]\",\n                ) from e\n            if name != package.name:\n                raise PylockValidationError(\n                    f\"Name in {wheel.filename!r} is not consistent with \"\n                    f\"package name {package.name!r}\",\n                    context=f\"wheels[{i}]\",\n                )\n            if package.version and version != package.version:\n                raise PylockValidationError(\n                    f\"Version in {wheel.filename!r} is not consistent with \"\n                    f\"package version {str(package.version)!r}\",\n                    context=f\"wheels[{i}]\",\n                )\n        if package.sdist:\n            try:\n                name, version = parse_sdist_filename(package.sdist.filename)","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/pylock.py#L599-L635","documentation":"A PylockValidationError raised during Package validation (Pylock.from_dict / Pylock.validate) when parse_wheel_filename cannot parse a [[packages.wheels]].filename. PEP 751 (pylock.toml) requires every wheel filename to follow the canonical 'name-version-pythontag-abitag-platformtag.whl' shape, so a structurally malformed string is rejected before any selection happens.","triggerScenarios":"Calling Pylock.from_dict(toml_dict) or Pylock.validate() on a lock whose [[packages.wheels]] entry has a filename like 'foo.whl' (missing version/tag segments), 'foo-1.0.tar.gz' (sdist extension on a wheel entry), or 'Foo--py3-none-any.whl' (empty version). The context field is 'wheels[i]' pointing at the offending entry index.","commonSituations":"Hand-edited pylock.toml, lock files emitted by an experimental/buggy lock generator, wheels renamed post-build (losing the canonical dash structure), or a wheel filename copied from a URL that included a trailing query/hash.","solutions":["Open pylock.toml and locate the wheel entry named in the error's context (e.g. wheels[2]); read its filename field.","Rewrite the filename to the canonical wheel pattern name-version-{pythontag}-{abitag}-{platformtag}.whl, e.g. 'requests-2.31.0-py3-none-any.whl'.","If unsure of the exact tag segments, regenerate the lock file with the original lock-producing tool rather than editing by hand.","Re-run Pylock.from_dict / Pylock.validate to confirm the error is gone before calling select()."],"exampleFix":"# before\n[[packages]]\nname = \"requests\"\nversion = \"2.31.0\"\n  [[packages.wheels]]\n  filename = \"requests-2.31.0.whl\"\n\n# after\n[[packages]]\nname = \"requests\"\nversion = \"2.31.0\"\n  [[packages.wheels]]\n  filename = \"requests-2.31.0-py3-none-any.whl\"","handlingStrategy":"validation","validationCode":"from packaging.utils import parse_wheel_filename\n\ndef is_valid_wheel_filename(filename: str) -> bool:\n    try:\n        parse_wheel_filename(filename)\n        return True\n    except Exception:\n        return False\n\n# before Pylock.from_dict, scrub every wheel filename:\nfor p in toml_dict.get('packages', []):\n    for w in p.get('wheels', []) or []:\n        if not is_valid_wheel_filename(w['filename']):\n            raise ValueError(f\"bad wheel filename: {w['filename']!r}\")","typeGuard":"null","tryCatchPattern":"from packaging.pylock import Pylock, PylockValidationError\ntry:\n    pylock = Pylock.from_dict(toml_dict)\nexcept PylockValidationError as e:\n    # e.context like 'packages[2].wheels[1]'; e.message is the human text\n    log.error(\"lock validation failed at %s: %s\", e.context, e.message)\n    raise","preventionTips":["Always obtain pylock.toml from a trusted locker rather than editing filenames by hand.","Run Pylock.validate() right after loading and surface the context field to localize the bad entry.","Add a pre-commit check that calls parse_wheel_filename on every wheel filename in the lock."],"tags":["pylock","packaging","validation","filename","wheel"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}