I am trying to use the pypa/gh-action-pypi-publish action in GitHub to push a Python package to PyPI. I'm in the team that owns microbiomedata/nmdc-schema and successfully uses a GitHub action to deploy the nmdc-schema. I have also read PyPA's advice and tried to follow it precisely.

However, when it comes to authenticating against PyPI, I get this "no matter what I do"

Run pypa/[email protected]
    user: __token__
    password: ${ secrets.pypi_password }
    packages_dir: dist
    verify_metadata: true
    pythonLocation: /opt/hostedtoolcache/Python/3.8.11/x64
    LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.8.11/x64/lib
/usr/bin/docker run --name a33c111d135a08e424daf8f55d57f9438a27b_084f0c --label 8a33c1 --workdir /github/workspace --rm -e pythonLocation -e LD_LIBRARY_PATH -e INPUT_USER -e INPUT_PASSWORD -e INPUT_REPOSITORY_URL -e INPUT_PACKAGES_DIR -e INPUT_VERIFY_METADATA -e HOME -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RETENTION_DAYS -e GITHUB_ACTOR -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_OS -e RUNNER_TOOL_CACHE -e RUNNER_TEMP -e RUNNER_WORKSPACE -e ACTIONS_RUNTIME_URL -e ACTIONS_RUNTIME_TOKEN -e ACTIONS_CACHE_URL -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/linkml-template-audit/linkml-template-audit":"/github/workspace" 8a33c1:11d135a08e424daf8f55d57f9438a27b  "__token__" "${ secrets.pypi_password }" "" "dist" "true"
Warning:  It looks like you are trying to use an API token to authenticate in the package index and your token value does not start with "pypi-" as it typically should. This may cause an authentication error. Please verify that you have copied your token properly if such an error occurs.
Checking dist/linkml_template_audit-0.0.1-py3-none-any.whl: PASSED, with warnings
  warning: `long_description_content_type` missing. defaulting to `text/x-rst`.
Checking dist/linkml_template_audit-0.0.1.tar.gz: PASSED, with warnings
  warning: `long_description_content_type` missing. defaulting to `text/x-rst`.
Uploading distributions to https://upload.pypi.org/legacy/
Uploading linkml_template_audit-0.0.1-py3-none-any.whl

  0%|          | 0.00/29.6k [00:00<?, ?B/s]
 27%|██▋       | 8.00k/29.6k [00:00<00:00, 48.7kB/s]
100%|██████████| 29.6k/29.6k [00:00<00:00, 107kB/s] 
NOTE: Try --verbose to see response content.
HTTPError: 403 Forbidden from https://upload.pypi.org/legacy/
Invalid or non-existent authentication information. See https://pypi.org/help/#invalid-auth for more information.

3 Answers 3


I was only wrapping my PyPI secret token in one pair of curly brackets! Two are required, like

${{ secrets.nmdc_schema_pypi_token }}


In my case the issue was that I added secrets as "environment secret" rather than "repository secret", leaving the latter empty.


This happened for me in the following circumstances:

  • Forked a project in github
  • Added a secret for the fork
  • Pushed update to my fork, and created a PR
  • The PR action ran in the upstream project
  • Build failed, with the "does not start with pypi" error

Instead I created a branch directly in the upstream project (along with the secret token), and when I pushed the branch to the upstream project, it ran as expected and updated TestPyPi.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.