warehouse icon indicating copy to clipboard operation
warehouse copied to clipboard

HTTPError: 400 Only one sdist may be uploaded per release (when using --skip-existing)

Open nanonano opened this issue 1 year ago • 6 comments

Describe the bug Since 15th April my uploads to test.pypi.org have started failing with the error:

HTTPError: 400 Only one sdist may be uploaded per release.

Not sure if something has changed, I thought if the --skip-existing flag was set this was okay?

Below is the GitHub actions log output.

Run twine upload --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*
[2](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:2)
  twine upload --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*
[3](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:3)
  shell: /usr/bin/bash -e {0}
[4](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:4)
  env:
[5](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:5)
    pythonLocation: /opt/hostedtoolcache/Python/3.12.3/x[6](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:6)4
6
    PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.12.3/x64/lib/pkgconfig
[7](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:7)
    Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.3/x64
[8](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:8)
    Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.3/x64
[9](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:9)
    Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.3/x64
[10](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:10)
    LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.3/x64/lib
[11](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:11)
    TWINE_USERNAME: __token__
[12](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:12)
    TWINE_PASSWORD: ***
[13](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:14)
Uploading distributions to https://test.pypi.org/legacy/
[14](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:15)
Uploading BittyTax-0.5.3.dev3-py3-none-any.whl
[15](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:16)
25l
[16](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:17)
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/935.3 kB • --:-- • ?
[17](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:18)
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/935.3 kB • --:-- • ?
[18](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:19)
 28% ━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 262.1/935.3 kB • 00:01 • 3.1 MB/s
[19](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:20)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.3/935.3 kB • 00:00 • 5.7 MB/s
[20](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:21)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.3/935.3 kB • 00:00 • 5.7 MB/s
[21](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:22)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.3/935.3 kB • 00:00 • 5.7 MB/s
[22](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:23)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.3/935.3 kB • 00:00 • 5.7 MB/s
[23](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:24)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 935.3/935.3 kB • 00:00 • 5.7 MB/s
[24](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:25)
25hWARNING  Skipping BittyTax-0.5.3.dev3-py3-none-any.whl because it appears to    
[25](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:26)
         already exist                                                          
[26](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:27)
Uploading bittytax-0.5.3.dev3.tar.gz
[27](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:28)
25l
[28](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:29)
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/910.7 kB • --:-- • ?
[29](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:30)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 910.7/910.7 kB • 00:00 • 224.2 MB/s
[30](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:31)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 910.7/910.7 kB • 00:00 • 224.2 MB/s
[31](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:32)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 910.7/910.7 kB • 00:00 • 224.2 MB/s
[32](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:33)
25hWARNING  Error during upload. Retry with the --verbose option for more details. 
[33](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:34)
ERROR    HTTPError: 400 Bad Request from https://test.pypi.org/legacy/          
[34](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:35)
         Only one sdist may be uploaded per release.                            
[35](https://github.com/BittyTax/BittyTax/actions/runs/8754325941/job/24025816451#step:6:36)
Error: Process completed with exit code 1.

Expected behavior

I would expect just the warning as before:

WARNING Skipping BittyTax-0.5.3.dev3.tar.gz because it appears to already exist

Run twine upload --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*
[2](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:2)
  twine upload --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*
[3](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:3)
  shell: /usr/bin/bash -e {0}
[4](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:4)
  env:
[5](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:5)
    pythonLocation: /opt/hostedtoolcache/Python/3.12.2/x[6](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:6)4
6
    PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.12.2/x64/lib/pkgconfig
[7](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:7)
    Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.2/x64
[8](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:8)
    Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.2/x64
[9](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:9)
    Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.2/x64
[10](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:10)
    LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.2/x64/lib
[11](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:11)
    TWINE_USERNAME: __token__
[12](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:12)
    TWINE_PASSWORD: ***
[13](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:14)
Uploading distributions to https://test.pypi.org/legacy/
[14](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:15)
Uploading BittyTax-0.5.3.dev3-py3-none-any.whl
[15](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:16)
25l
[16](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:17)
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/928.6 kB • --:-- • ?
[17](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:18)
 65% ━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━ 606.2/928.6 kB • 00:01 • 30.0 MB/s
[18](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:19)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 928.6/928.6 kB • 00:00 • 36.8 MB/s
[19](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:20)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 928.6/928.6 kB • 00:00 • 36.8 MB/s
[20](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:21)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 928.6/928.6 kB • 00:00 • 36.8 MB/s
[21](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:22)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 928.6/928.6 kB • 00:00 • 36.8 MB/s
[22](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:23)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 928.6/928.6 kB • 00:00 • 36.8 MB/s
[23](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:24)
25hWARNING  Skipping BittyTax-0.5.3.dev3-py3-none-any.whl because it appears to    
[24](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:25)
         already exist                                                          
[25](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:26)
Uploading BittyTax-0.5.3.dev3.tar.gz
[26](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:27)
25l
[27](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:28)
  0% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/905.3 kB • --:-- • ?
[28](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:29)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 905.3/905.3 kB • 00:00 • 155.5 MB/s
[29](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:30)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 905.3/905.3 kB • 00:00 • 155.5 MB/s
[30](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:31)
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 905.3/905.3 kB • 00:00 • 155.5 MB/s
[31](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:6:32)
25hWARNING  Skipping BittyTax-0.5.3.dev3.tar.gz because it appears to already exist

To Reproduce

My Platform

Current runner version: '2.315.0'
[2](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:2)
Operating System
[3](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:3)
  Ubuntu
[4](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:4)
  22.04.4
[5](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:5)
  LTS
[6](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:7)
Runner Image
[7](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:8)
  Image: ubuntu-22.04
[8](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:9)
  Version: 20240407.1.0
[9](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:10)
  Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20240407.1/images/ubuntu/Ubuntu2204-Readme.md
[10](https://github.com/BittyTax/BittyTax/actions/runs/8629194815/job/23652859082#step:1:11)
  Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20240407.1

Additional context None

nanonano avatar Apr 19 '24 13:04 nanonano

The issue here seems to be the difference between bittytax-0.5.3.dev3.tar.gz (which is what you're trying to upload) and BittyTax-0.5.3.dev3.tar.gz (what you've already uploaded).

Packaging considers these the same file, because:

>>> from packaging.utils import parse_sdist_filename
>>> parse_sdist_filename('bittytax-0.5.3.dev3.tar.gz') == parse_sdist_filename('BittyTax-0.5.3.dev3.tar.gz')
True

but it looks like the logic in twine doesn't take this normalization into account: https://github.com/pypa/twine/blob/67e87ef4221123454403b11ee8f802e87fcc13fd/twine/repository.py#L229

...so it doesn't correctly skip the upload and attempts to do it anyways.

Our error message here is a little confusing though, because we also don't take normalization into account when checking for duplicate filenames:

https://github.com/pypi/warehouse/blob/5a2d6f8b9d8e27be52973093a690ab7a9b7c1d84/warehouse/forklift/legacy.py#L910-L939

And so this fails on our check for multiple source distributions instead:

https://github.com/pypi/warehouse/blob/5a2d6f8b9d8e27be52973093a690ab7a9b7c1d84/warehouse/forklift/legacy.py#L941-L953

Fixing this is probably blocked on https://github.com/pypi/warehouse/issues/12245, since there is not such a thing as a normalized source distribution filename in every case until that is resolved.

di avatar Apr 19 '24 18:04 di

Thanks for this, I didn't release the filename of the tar file had been changed to lowercase.

Now I need to figure out what has caused this change, the versions of build (1.2.1) and twine (5.0.0) are the same.

nanonano avatar Apr 19 '24 20:04 nanonano

The change is caused by tools starting to support PEP 625. In your case, it is probably setuptools. In your case, bittytax-0.5.3.dev3.tar.gz is now the "right" filename for this, and nothing should change there.

Once #12245 is fixed, this should go away, and there's probably nothing you need to do here in the meantime.

di avatar Apr 19 '24 20:04 di

OK great that explains it, thanks for your help.

I'll probably just up-version to get around the issue.

nanonano avatar Apr 19 '24 20:04 nanonano

I don't know if this is also related to PEP 625, but I also tried to upload a package to test.pypi.org (using pypa/gh-action-pypi-publish@release/v1 with skip-existing: true, which is the same as twine --skip-existing), and I got:

ERROR    HTTPError: 400 Bad Request from https://test.pypi.org/legacy/          
         Only one sdist may be uploaded per release.  

I would have expected a warning.

At https://test.pypi.org/project/sphinxcontrib-opencontracting/#files, I can see that the sdist has two hyphens: sphinxcontrib-opencontracting-0.0.9.tar.gz

The file being uploaded (built with python -m build --sdist --wheel) has a hyphen only before the version: sphinxcontrib_opencontracting-0.0.9.tar.gz

Verbose info from pypa/gh-action-pypi-publish@release/v1 step:

Checking dist/sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl: PASSED
Checking dist/sphinxcontrib_opencontracting-0.0.9.tar.gz: PASSED
Showing hash values of files to be uploaded:
/github/workspace/dist/sphinxcontrib_opencontracting-0.0.9.tar.gz

SHA256: 996837ed8abf4deb4938d4047dfe34de9a344e9ccfc005e538aee63be3e40c59
MD5: 2e4562014c683e026030b279b37189cb
BLAKE2-256: 32d0ce3c9412efbcb69bc1022d66b78b36012c4c196b6a5812cb3d1c1e3bf432

/github/workspace/dist/sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl

SHA256: 2c1e3b6ec6f0ad29444cd149b650ac294df6e74fb5a745b6600429cb207104f6
MD5: 2ecad59c1d2f9e94fee80bbc0ae96b4f
BLAKE2-256: fa081a293eb89ce2a5720bb0275c37b390b49d47bc4c063a7bd73a7b38faae60

Uploading distributions to https://test.pypi.org/legacy/
INFO     dist/sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl (10.1 KB)    
INFO     dist/sphinxcontrib_opencontracting-0.0.9.tar.gz (13.8 KB)              
INFO     password set by command options                                        
INFO     username: __token__                                                    
INFO     password: <hidden>                                                     
Uploading sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl
INFO     Response from https://test.pypi.org/legacy/:                           
         400 File already exists                                                
         ('sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl', with          
         blake2_256 hash                                                        
         'fa081a293eb89ce2a5720bb0275c37b390b49d47bc4c063a7bd73a7b38faae60').   
         See https://test.pypi.org/help/#file-name-reuse for more information.  
INFO     <html>                                                                 
          <head>                                                                
           <title>400 File already exists                                       
         ('sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl', with          
         blake2_256 hash                                                        
         'fa081a293eb89ce2a5720bb0275c37b390b49d47bc4c063a7bd73a7b38faae60').   
         See https://test.pypi.org/help/#file-name-reuse for more               
         information.</title>                                                   
          </head>                                                               
          <body>                                                                
           <h1>400 File already exists                                          
         ('sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl', with          
         blake2_256 hash                                                        
         'fa081a293eb89ce2a5720bb0275c37b390b49d47bc4c063a7bd73a7b38faae60').   
         See https://test.pypi.org/help/#file-name-reuse for more               
         information.</h1>                                                      
           The server could not comply with the request since it is either      
         malformed or otherwise incorrect.<br/><br/>                            
         File already exists                                                    
         (&#x27;sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl&#x27;, with
         blake2_256 hash                                                        
         &#x27;fa081a293eb89ce2a5720bb0275c37b390b49d47bc4c063a7bd73a7b38faae60&
         #x27;). See https://test.pypi.org/help/#file-name-reuse for more       
         information.                                                           
                                                                                
                                                                                
          </body>                                                               
         </html>                                                                
WARNING  Skipping sphinxcontrib_opencontracting-0.0.9-py3-none-any.whl because  
         it appears to already exist                                            
Uploading sphinxcontrib_opencontracting-0.0.9.tar.gz
INFO     Response from https://test.pypi.org/legacy/:                           
         400 Only one sdist may be uploaded per release.                        
INFO     <html>                                                                 
          <head>                                                                
           <title>400 Only one sdist may be uploaded per release.</title>       
          </head>                                                               
          <body>                                                                
           <h1>400 Only one sdist may be uploaded per release.</h1>             
           The server could not comply with the request since it is either      
         malformed or otherwise incorrect.<br/><br/>                            
         Only one sdist may be uploaded per release.                            
                                                                                
                                                                                
          </body>                                                               
         </html>                                                                
ERROR    HTTPError: 400 Bad Request from https://test.pypi.org/legacy/          
         Only one sdist may be uploaded per release.                            

jpmckinney avatar Sep 07 '24 08:09 jpmckinney

Yes, that is due to what I mentioned above:

Our error message here is a little confusing though, because we also don't take normalization into account when checking for duplicate filenames:

And so this fails on our check for multiple source distributions instead

di avatar Sep 12 '24 22:09 di