{"id":"22e375c695b9cb69","repo":"python-poetry/poetry","slug":"filename-is-not-a-valid-wheel-filename","errorCode":null,"errorMessage":"{filename} is not a valid wheel filename.","messagePattern":"(.+?) is not a valid wheel filename\\.","errorType":"exception","errorClass":"InvalidWheelNameError","httpStatus":null,"severity":"error","filePath":"src/poetry/utils/wheel.py","lineNumber":27,"sourceCode":"from poetry.utils.patterns import wheel_file_re\n\n\nif TYPE_CHECKING:\n    from poetry.utils.env import Env\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass InvalidWheelNameError(Exception):\n    pass\n\n\nclass Wheel:\n    def __init__(self, filename: str) -> None:\n        wheel_info = wheel_file_re.match(filename)\n        if not wheel_info:\n            raise InvalidWheelNameError(f\"{filename} is not a valid wheel filename.\")\n\n        self.filename = filename\n        self.name = wheel_info.group(\"name\").replace(\"_\", \"-\")\n        self.version = wheel_info.group(\"ver\").replace(\"_\", \"-\")\n        self.build_tag = wheel_info.group(\"build\")\n        self.pyversions = wheel_info.group(\"pyver\").split(\".\")\n        self.abis = wheel_info.group(\"abi\").split(\".\")\n        self.plats = wheel_info.group(\"plat\").split(\".\")\n\n        self.tags = {\n            Tag(x, y, z) for x in self.pyversions for y in self.abis for z in self.plats\n        }\n\n    def get_minimum_supported_index(self, tags: list[Tag]) -> int | None:\n        indexes = [tags.index(t) for t in self.tags if t in tags]\n\n        return min(indexes) if indexes else None\n","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/utils/wheel.py#L9-L45","documentation":"Wheel.__init__ matches the filename against wheel_file_re (PEP 427 layout: {name}-{ver}(-{build})?-{pyver}-{abi}-{plat}.whl). If the regex does not match it raises InvalidWheelNameError. The filename must contain all five required dash-separated tag fields plus the .whl suffix.","triggerScenarios":"Constructing Wheel('foo.txt'), Wheel('foo-1.0.tar.gz') (sdist), or a wheel missing tag fields like 'foo-1.0.whl' or 'foo-1.0-py3-none-any' (no extension).","commonSituations":"Passing a non-wheel filename to Wheel; a truncated/renamed download; a wheel produced by non-standard tooling that omits the build tag delimiter; filename with unescaped dashes confusing the regex.","solutions":["Verify the filename conforms to PEP 427 (all of name, version, python tag, abi tag, platform tag, and .whl).","Re-download the wheel from the publisher or rebuild it with `pip wheel`/`python -m build`.","Do not feed sdist/source paths to Wheel(); use Wheel only for .whl files."],"exampleFix":"# before\nWheel('requests-2.31.whl')          # missing tag fields -> InvalidWheelNameError\n# after\nWheel('requests-2.31.0-py3-none-any.whl')","handlingStrategy":"validation","validationCode":"from poetry.utils.patterns import wheel_file_re\n\ndef is_valid_wheel_filename(filename: str) -> bool:\n    return wheel_file_re.match(filename) is not None","typeGuard":"from poetry.utils.patterns import wheel_file_re\n\ndef is_wheel_filename(filename: str) -> bool:\n    return filename.endswith('.whl') and wheel_file_re.match(filename) is not None","tryCatchPattern":"from poetry.utils.wheel import InvalidWheelNameError, Wheel\ntry:\n    w = Wheel(filename)\nexcept InvalidWheelNameError:\n    # not a wheel; handle as sdist/source or reject\n    raise","preventionTips":["Match against wheel_file_re before constructing Wheel.","Only pass genuine .whl filenames; route sdists elsewhere.","Re-download wheels from the publisher if a filename looks truncated."],"tags":["wheel","packaging","pep427","validation"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}