无法上传Python包至PyPI:400 Bad Request错误求助
问题:上传Python包至PyPI时出现400错误(POST body may not contain duplicate keys)
环境与已完成操作
- 执行
python setup.py sdist bdist_wheel生成两个分发文件:PACKAGENAME-0.1.1-py3-none-any.whl PACKAGENAME-0.1.1.tar.gz setup.py配置内容:from setuptools import setup, find_packages setup( name='PACKAGE NAME', version='0.1.1', author='blackthorne18', description='Testing package', url='GITHUBURL', #指向该包的GitHub公开仓库 py_modules=['entrypoint', 'runscript'], packages=find_packages(), install_requires=[requirements], python_requires='>=3.10', classifiers=[ "Programming Language :: Python :: 3.10", "Operating System :: OS Independent", ], entry_points=''' [console_scripts] PACKAGE=entrypoint:main ''' )- 已通过
$HOME/.pypirc配置Token身份验证,成功上传至test.pypi:$ twine upload --repository testpypi dist/* --verbose Uploading PACKAGENAME-0.1.1.tar.gz 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 27.8/27.8 kB • 00:00 • 29.3 MB/s INFO Response from https://test.pypi.org/legacy/: 200 OK INFO <html> <head> <title>200 OK</title> </head> <body> <h1>200 OK</h1> <br/><br/> </body> </html> View at: https://test.pypi.org/project/PACKAGENAME/0.1.1/
错误现象
上传至PyPI官方仓库时触发400错误:
$ twine upload dist/* --verbose Uploading PACKAGENAME-0.1.1-py3-none-any.whl 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 27.9/27.9 kB • 00:00 • 16.0 MB/s INFO Response from https://upload.pypi.org/legacy/: 400 Bad Request INFO <html> <head> <title>400 Bad Request</title> </head> <body> <h1>400 Bad Request</h1> The server could not comply with the request since it is either malformed or otherwise incorrect.<br/><br/> POST body may not contain duplicate keys </body> </html> ERROR HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/ Bad Request
执行twine check dist/*显示两个分发文件均检查通过。
版本信息
python version 3.10 twine version 4.0.1 (importlib-metadata: 5.0.0, keyring: 23.11.0, pkginfo: 1.8.3, requests: 2.28.1, requests-toolbelt: 0.10.1, urllib3: 1.26.12)
修复方案
1. 移除setup.py中的重复配置项
PyPI对元数据的校验比test.pypi更严格,你的setup.py同时使用py_modules和find_packages()会导致生成的元数据出现重复键,触发错误。根据你的包结构二选一:
- 若打包单个模块文件:保留
py_modules,删除packages=find_packages() - 若打包完整项目包:保留
packages=find_packages(),删除py_modules
示例修改后的setup.py(以完整项目包为例):
from setuptools import setup, find_packages setup( name='PACKAGE NAME', version='0.1.1', author='blackthorne18', description='Testing package', url='GITHUBURL', #指向该包的GitHub公开仓库 packages=find_packages(), install_requires=[requirements], python_requires='>=3.10', classifiers=[ "Programming Language :: Python :: 3.10", "Operating System :: OS Independent", ], entry_points=''' [console_scripts] PACKAGE=entrypoint:main ''' )
2. 重新生成分发文件
清理旧构建文件后重新打包:
rm -rf dist/ build/ *.egg-info python setup.py sdist bdist_wheel
3. 重新上传至PyPI
twine upload dist/* --verbose
额外排查点
- 检查
install_requires中的requirements是否存在重复依赖定义 - 升级twine到最新版本,修复旧版本可能存在的元数据处理bug:
pip install --upgrade twine
内容的提问来源于stack exchange,提问作者blackthorne18
相关产品推荐
相关产品推荐

