Repository navigation
Closed
Labels
Description
Bug Report
Description
We have a github actions workflow to create releases. A few days ago it suddenly stopped working and it seems related to the new verify upstream unchanged feature. See job definition below. We suspected the persist-credentials: false option to the checkout action, and while removing that option does make the fetch go through, the build then instead fails at the push step because the (presumably default) token has insufficient credentials.
Expected behavior
This is the output from a run at November 7th, presumably using PSR 10.4.1:
Details
[...]
Installed 30 packages in 27ms
2.1.0
The next version is: 2.1.0! 🚀
Skipping build due to --skip-build flag
Using CPython 3.12.3 interpreter at: /usr/bin/python3.12
[...]
2.1.0
The next version is: 2.1.0! 🚀
🛠 Running build command: uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/[redacted]-2.1.0.tar.gz
Successfully built dist/[redacted]-2.1.0-py3-none-any.whl
Build completed successfully!
Actual behavior
This is the output today, using PSR 10.5.2:
Details
2.1.1
The next version is: 2.1.1! 🚀
Skipping build due to --skip-build flag
Using CPython 3.12.3 interpreter at: /usr/bin/python3.12
[...]
2.1.1
The next version is: 2.1.1! 🚀
🛠 Running build command: uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/[redacted]-2.1.1.tar.gz
Successfully built dist/[redacted]-2.1.1-py3-none-any.whl
Build completed successfully!
[08:37:16] ERROR Cmd('git') failed due to: exit code(128) gitproject.py:414
cmdline: git fetch -v -- origin
stderr: 'fatal: could not read Username
for 'https://github.com/': No such device
or address'
╭── Traceback (most recent call last) ───╮
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/zCqNxvksJxPI6MA7YgzqA/lib/ │
│ python3.12/site-packages/semantic_rele │
│ ase/gitproject.py:412 in │
│ verify_upstream_unchanged │
│ │
│ 409 │ │ │ # Fetch the latest c │
│ 410 │ │ │ self.logger.info("Fe │
│ 411 │ │ │ try: │
│ ❱ 412 │ │ │ │ remote_ref_obj.f │
│ 413 │ │ │ except GitCommandErr │
│ 414 │ │ │ │ self.logger.exce │
│ 415 │ │ │ │ err_msg = f"Fail │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/zCqNxvksJxPI6MA7YgzqA/lib/ │
│ python3.12/site-packages/git/remote.py │
│ :1076 in fetch │
│ │
│ 1073 │ │ proc = self.repo.git.fe │
│ 1074 │ │ │ "--", self, *args, │
│ universal_newlines=True, v=verb │
│ 1075 │ │ ) │
│ ❱ 1076 │ │ res = self._get_fetch_i │
│ kill_after_timeout=kill_after_t │
│ 1077 │ │ if hasattr(self.repo.od │
│ 1078 │ │ │ self.repo.odb.updat │
│ 1079 │ │ return res │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/zCqNxvksJxPI6MA7YgzqA/lib/ │
│ python3.12/site-packages/git/remote.py │
│ :902 in _get_fetch_info_from_stderr │
│ │
│ 899 │ │ ) │
│ 900 │ │ │
│ 901 │ │ stderr_text = progress. │
│ ❱ 902 │ │ proc.wait(stderr=stderr │
│ 903 │ │ if stderr_text: │
│ 904 │ │ │ _logger.warning("Er │
│ 905 │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/zCqNxvksJxPI6MA7YgzqA/lib/ │
│ python3.12/site-packages/git/cmd.py:41 │
│ 9 in wait │
│ │
│ 416 │ │ if status != 0: │
│ 417 │ │ │ errstr = read_all_f │
│ 418 │ │ │ _logger.debug("Auto │
│ ❱ 419 │ │ │ raise GitCommandErr │
│ 420 │ │ return status │
│ 421 │
│ 422 │
╰────────────────────────────────────────╯
GitCommandError: Cmd('git') failed due to:
exit code(128)
cmdline: git fetch -v -- origin
stderr: 'fatal: could not read Username
for 'https://github.com/': No such device
or address'
Failed to fetch from remote 'origin'
Unable to verify upstream due to error!
And this is the output after removing persist-credentials: false:
Details
2.1.1
The next version is: 2.1.1! 🚀
Skipping build due to --skip-build flag
Using CPython 3.12.3 interpreter at: /usr/bin/python3.12
[...]
2.1.1
The next version is: 2.1.1! 🚀
🛠 Running build command: uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/<redacted>-2.1.1.tar.gz
Successfully built dist/<redacted>-2.1.1-py3-none-any.whl
Build completed successfully!
[09:26:52] ERROR Cmd('git') failed due to: exit code(1) gitproject.py:312
cmdline: git push
***github.com/<redacted>.git main
stderr: 'remote: error: GH013:
Repository rule violations found for
refs/heads/main.
remote: Review all repository rules at
https://github.com/<redacted>/rules
?ref=refs%2Fheads%2Fmain
remote:
remote: - Changes must be made through a
pull request.
remote:
To
https://github.com/<redacted>.git
! [remote rejected] main -> main (push
declined due to repository rule
violations)
error: failed to push some refs to
'https://github.com/<redacted>.git'
'
╭── Traceback (most recent call last) ───╮
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/RSMkjl3R3t64vpgxKv1Ws/lib/ │
│ python3.12/site-packages/semantic_rele │
│ ase/gitproject.py:310 in │
│ git_push_branch │
│ │
│ 307 │ │ │
│ 308 │ │ with Repo(str(self.proje │
│ 309 │ │ │ try: │
│ ❱ 310 │ │ │ │ repo.git.push(re │
│ 311 │ │ │ except GitCommandErr │
│ 312 │ │ │ │ self.logger.exce │
│ 313 │ │ │ │ raise GitPushErr │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/RSMkjl3R3t64vpgxKv1Ws/lib/ │
│ python3.12/site-packages/git/cmd.py:10 │
│ 03 in <lambda> │
│ │
│ 1000 │ │ """ │
│ 1001 │ │ if name.startswith("_") │
│ 1002 │ │ │ return super().__ge │
│ ❱ 1003 │ │ return lambda *args, ** │
│ 1004 │ │
│ 1005 │ def set_persistent_git_opti │
│ 1006 │ │ """Specify command line │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/RSMkjl3R3t64vpgxKv1Ws/lib/ │
│ python3.12/site-packages/git/cmd.py:16 │
│ 16 in _call_process │
│ │
│ 1613 │ │ call.append(dashify(met │
│ 1614 │ │ call.extend(args_list) │
│ 1615 │ │ │
│ ❱ 1616 │ │ return self.execute(cal │
│ 1617 │ │
│ 1618 │ def _parse_object_header(se │
│ 1619 │ │ """ │
│ │
│ /home/runner/work/_temp/setup-uv-cache │
│ /archive-v0/RSMkjl3R3t64vpgxKv1Ws/lib/ │
│ python3.12/site-packages/git/cmd.py:14 │
│ 06 in execute │
│ │
│ 1403 │ │ # END handle debug prin │
│ 1404 │ │ │
│ 1405 │ │ if with_exceptions and │
│ ❱ 1406 │ │ │ raise GitCommandErr │
│ 1407 │ │ │
│ 1408 │ │ if isinstance(stdout_va │
│ output_stream. │
│ 1409 │ │ │ stdout_value = safe │
╰────────────────────────────────────────╯
GitCommandError: Cmd('git') failed due to:
exit code(1)
cmdline: git push
***github.com/<redacted>.git main
stderr: 'remote: error: GH013:
Repository rule violations found for
refs/heads/main.
remote: Review all repository rules at
https://github.com/<redacted>/rules
?ref=refs%2Fheads%2Fmain
remote:
remote: - Changes must be made through a
pull request.
remote:
To
https://github.com/<redacted>.git
! [remote rejected] main -> main (push
declined due to repository rule
violations)
error: failed to push some refs to
'https://github.com/<redacted>.git'
'
- Operating System (w/ version): Ubuntu 24.04.3 LTS
- Python version: 3.12.3
- Pip version: unknown
- Semantic-release version: 10.5.2
- Build tool (w/ version): uv
Configuration
Semantic Release Configuration
[tool.semantic_release]
branch = "main"
build_command = "uv build"
commit_message = "chore(release): v{version} [skip ci]"
commit_version_number = true
upload_to_pypi = false
upload_to_release = true
upload_to_repository = false
version_source = "tag"
version_toml = ["pyproject.toml:project.version"]
[tool.semantic_release.commit_parser_options]
allowed_tags = [
"build",
"chore",
"ci",
"docs",
"feat",
"fix",
"perf",
"refactor",
"style",
"test",
]
minor_tags = ["feat"]
patch_tags = ["build", "chore", "ci", "fix", "perf", "test"]
GitHub Actions Job Definition
jobs:
release:
runs-on: ubuntu-latest
outputs:
released: ${{ steps.release.outputs.released }}
tag: ${{ steps.release.outputs.tag }}
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: "Setup Python & UV"
[...]
- name: Python Semantic Release
id: release
run: |
git config --global user.name "github-actions"
git config --global user.email "[email protected]"
uvx python-semantic-release=="10.*" version --skip-build --no-commit --no-tag --no-changelog
uv lock
git add uv.lock
uvx python-semantic-release=="10.*" version
env:
GH_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }}
- name: Publish package distributions to GitHub Releases
if: steps.release.outputs.released == 'true'
run: |
uvx python-semantic-release=="10.*" publish --tag "${{steps.release.outputs.tag}}"
env:
GH_TOKEN: ${{ github.token }}Reacted by weisiang9678
Activity
codejedi365 commentedon Nov 11, 2025
Thank you for reporting your issue as contributing to PSR only helps make PSR better.
My analysis (request response to my assumptions & diagnosis if I am incorrect):
The final error is the most telling as it identifies that you have branch restrictions on main (
Repository rule violations found for refs/heads/main...Changes must be made through a pull request.). Branch restrictions are very difficult to work through with PSR's release commit mechanism without some additional configuration. Until recently, I did not have a solution for branch protections until Bypass protected branches with deploy keys #1343 besides what you are doing with a custom PAT and I assume you have bypass restrictions enabled for that token?Estyrke's workflow does not limit or define GITHUB_TOKEN permissions which means it has all write permissions to authorized CI API endpoints. Required permissions for release committing PSR are
contents: write. Estyrke setspersist-credentials: falseto remove GITHUB_TOKEN from git configuration. This causesgit fetchto fail as the git repository does not have credentials to the repository any more and PSR'sgit fetchdoes not use a credentialed url as part of fetch, it expects origin the git repository to be authenticated (unlike PSR's git push).[Possible PSR feature patch] If the git fetch used the same mechanism as PSR's git push it would use the custom
secrets.SEMANTIC_RELEASE_GITHUB_TOKENas part of the fetch url and it would have read access to the repository to validate the upstream has not changed prior to the release commitgit push. Requires the settingtool.semantic_release.remote.ignore_token_for_push = falsefor success.[Possible PSR bug] When
actions/checkoutis providedpersist-credentials: true(default), thegit fetchused to verify the upstream has not changed succeeds because the git repo hascontents: writevia the fully-authorizedGITHUB_TOKEN. This allows PSR to continue to thegit push https://$GITHUB_ACTOR:$TOKEN@$ORIGIN_URL mainstep and this fails supposedly because of the branch protections on main (Changes must be made through a pull request.). Based on github.py#L477:L487, my expectation is that$TOKENisSEMANTIC_RELEASE_GITHUB_TOKENbecause token is passed in from the configuration and not interpreted fromgit config --get remote.origin.urlwhich currently has the$GITHUB_TOKENvalue. This expectation is either wrong andGITHUB_TOKENtrips the branch protections, orSEMANTIC_RELEASE_GITHUB_TOKENdoes not have bypass permissions to push tomain. This is also dependent on the value oftool.semantic_release.remote.ignore_token_for_pushwhich should not be an issue as the default isfalse.Your workflow might not of had a
verify_upstreamscript (as recommended in example workflows) prior to executing PSR inv10.4.1. If so, it was possible that if the Actions workflow prior to the release job took too long, there could of been another push tomain. This situation would of caused an upstream collision in the git push of the release commit. PSR'sv10.5.2intent is to eliminate this situation without consumer need for a separateverify_upstreamstep and minimize the possible collision time window to milliseconds before push, but requires an authenticatedgit fetchmechanism.Your workflow is not specific on where the repo is checked out. It is unclear if
actions/checkoutis going to check out the ref or the sha directly. Given there is no branch checkout step included in your workflow, I assume it is checking outmainblindly. This is problematic as if there was another commit tomainin the duration of the workflow, it is likely a untested change will be released accidentally. PSR recommends settingref: ${{ github.sha }}on theactions/checkoutstep which sets the repo in a detached head state but deliberately on the commit that was validated through prior actions test jobs. Then add a step to deliberately check out the correct release branch at that commit sha (ex.git checkout -B ${{ github.ref_name }}).The
fetch-depth: 0parameter is no longer required as of[email protected]since functionality has been added to automatically un-shallow repositories as long as the git repository is credentialed. This will also fail in your workflow as the authorized git access to the remote has been severed.Your semantic release configuration still has some old configuration options that no longer exist. Specifically,
commit_version_number,upload_to_pypi,upload_to_repository, andversion_sourcedo not exist. The settingupload_to_releasehas been moved totool.semantic_release.publish.upload_to_vcs_release. This likely occurred in the transition fromv7tov8and unfortunately PSR's config parser does not alert you of these mismatches (an update is under development). Recommend running the following command to cross-check your desired results with the new defaults:After this analysis, I think we can make your situation work if you wanted to change the CI implementation significantly (and maybe try deploy keys as that seems the most ideal for security GitHub solution) but I likely will also need to implement the patch to use an authenticated git fetch deliberately. I just didn't have this in mind and honestly have been confused at the use case for the current
git pushwith an authenticated url rather than justorigin. After seeing your workflow, now I see the situation.estyrke commentedon Nov 12, 2025
Yes, correct.
I am a bit confused by this as well. Even if "persist-credentials" is true, PSR should reasonably use the provided GH_TOKEN for the push, but apparently it gets overridden somehow (due to .insteadOf magic added to the git config by actions/checkout perhaps?)
Ouch! I have always assumed that actions/checkout checks out the ref that triggered the workflow...
Actually, this seems to be what it does according to the readme (emphasis mine):
Specifically, we use the 'workflow_call' trigger, which is supposed to use the same GITHUB_SHA as the caller, which in turn uses the
pushtrigger.Ideally both our current workflow (with non-persisted credentials and provided GH_TOKEN) and the one with persisted credentials, correctly applying the provided GH_TOKEN to the push command should work, but I'll look into updating our workflow according to best practices.
estyrke commentedon Nov 12, 2025
As an aside, I don't really see what the verify_upstream_unchanged functionality is supposed to accomplish. Wouldn't the push itself fail if there are new commits on the branch?
codejedi365 commentedon Nov 13, 2025
Yes, there should be a failure, but I'm not going to be parsing the error messages from github to help people determine why there was a failure. A few people have also asked for a force push option to get around the branch protections. In that case, there would be no error only destructive actions. I felt it was best to add a script beforehand as a recommended course of action and this release I integrated it into PSR so users didn't have to worry about it. This mechanism is a proactive way to detect when an error will occur and provide a descriptive user message of why no release occurred.
codejedi365 commentedon Nov 13, 2025
Although it says this, it is an incomplete statement. It says ref/SHA. The branch name is a ref and we know it is the branch because otherwise you would have a step that checks out the branch because PSR does not work on a detached head state. Detached head states occur when you
git checkout SHA. I also warn you of the exact situation above, because it happened with a release of PSR. I was lucky it did not break anything, but it released a commit that was added to the default branch after the releasing workflow was executing (during its testing phase). So when the two simultaneously running workflows were executing the first arrived at the release job and released the current state ofmastereven though I had aconcurrencyflag set. They may have updated it inv5but I'm pretty sure it still exists and it happened to me inv4, in the last 1.5 yrs.I don't disagree that the GITHUB_SHA is defined, I'm telling you that checkout does not use it if you leave it undefined.
estyrke commentedon Nov 13, 2025
It sounded like such an unreasonable behavior that I had to test it: https://github.com/estyrke/test-actions-checkout/actions
This shows that both for push and workflow_dispatch triggers, the
actions/checkout@v4action checks out the original commit that triggered the workflow even if there are commits added during the workflow run. That is if no ref input is provided, so that the default is used. If you specifyref: mainthe result may be different.rdctmeconomou commentedon Nov 15, 2025
Maybe it's unrelated, but I'm getting a similar error (
fatal: could not read Username for 'https://github.com/': No such device or address) for both versions 8.3.0 and 10.5.2 of the python-semantic-release/python-semantic-release action, which I upgraded as part of my troubleshooting:This worked on September 15 with version 8.3.0:
I double-checked the commit history and organization audit logs. Aside from me updating actions' version pins (in troubleshooting this issue) and editing a comment, my CI workflow hasn't changed. At the repository level, I've changed several GitHub Actions secrets and variables, but they only affect my deployment workflow. We recently subscribed to the GitHub Team plan, but that was three hours before the last successful execution of the action. I literally have the receipts. We aren't using branch protection rules or anything like that. I'm at a loss as to what might have gone wrong.
codejedi365 commentedon Nov 15, 2025
@rdctmeconomou, Is your git repository authenticated? Because a
git fetch originwas added inv10.5.Please provide your release job steps to show how you are setting up the repo prior to the release step.
rdctmeconomou commentedon Nov 15, 2025
@codejedi365 It doesn't contain anything proprietary, so here's the current workflow definition, which includes the changes I made while troubleshooting this issue, and here's the original version, which worked several months ago but is broken now.
The project lives in a private repository hosted by GitHub.com, so yes, access to it would require authentication. Note that the
lintjob uses a GitHub App to access private repositories containing project dependencies, but those credentials get discarded at the end of the job.codejedi365 commentedon Nov 15, 2025
@rdctmeconomou, reviewed your ci workflow. Your issue is similar because your git repository is unauthenticated prior to
python-semantic-releaseexecution. The fact you checkout the repo in a prior job, the post-checkout step removes the authentication fromgitat the end of the setup job and separately the cache does not return it when entering the release job. You would also need the patch I discussed above to use the passed github token to performgit fetch.To make it work today, you should revert to
v10.4.1.Other recommendations:
concurrency.cancel-in-progresssetting in the release job, you don't want to cancel mid release.actions/upload-artifactandactions/download-artifact.python-semantic-release/upload-to-gh-release@mainquite a while ago. Recommend switching to the new repository to maintain to compatibility of your PSR configuration. The new repo ispython-semantic-release/publish-action.codejedi365 commentedon Nov 15, 2025
I see what you did, but I don't think your workflow test is comprehensive enough to test the scenario that could occur. The fact you are in the same job, the provided
GITHUB_SHAhas no chance in changing. I have tested this when the example I discussed above occurred, and I used a sleep action in a test job and then manually pushed a change from my local machine before it moved on to a separate release job and at that point it did fail in a reproducible pattern. But, continue at your own risk.2 remaining items
fix(cmd-version): resolve unauthenticated git repo issues for upstrea…
fix(cmd-version): resolve unauthenticated git repo issues for upstrea…
fix(cmd-version): resolve unauthenticated git repo issues for upstrea…
fix(cmd-version): resolve unauthenticated git repo issues for upstrea…
fix(cmd-version): resolve unauthenticated git repo issues for upstrea…
[-]verify_upstream_unchanged fails on github actions[/-][+]`verify_upstream_unchanged` fails on github actions when git repo is unauthenticated[/+]codejedi365 commentedon Dec 14, 2025
🎉 This issue has been resolved in v10.5.3 🎉
You can find more information about this release on the GitHub Releases page.
If your issue persists, please reply here and we will re-open the issue. If you receive a new error, please open a new issue and reference this issue there.