pyGithub Pull request invalid head (422 API error)

Recently I've been trying to use pyGithub to create some automated PRs after running a make update in a bunch of repos using this snipppet.

body = 'Test PR 2 please ignore'
pr = repo.create_pull(title="Test PR please ignore",
                          body=body,
                          head="patch/helm-chart-update",
                          base="master")
pr

I've consistently gotten this error message back from the API

github.GithubException.GithubException: 422 {"message": "Validation Failed", "errors": [{"resource": "PullRequest", "field": "head", "code": "invalid"}], "documentation_url": "https://developer.github.com/v3/pulls/#create-a-pull-request"}

Naturally, my first guess was that I'd mistyped the repo name, but this wasn't the case. Strangely, I get an identical error when I replace the head name with a nonexistent branch name like 'someGarbage'.

Next, I thought perhaps there were conflicts or other invalidating details about the PR (even though it was extremely unlikely due to the simplicity of the test branch I was working with), but the Github GUI created the PR without any issues.

Ultimately I was able to make a PR using https://pypi.org/project/git-pull-request/ , but unfortunately I can't see a way to avoid it opening vim in the shell (which would create a lot of toil due to the number of repos this will run on). If all else fails, I'll likely just use requests to make a manual call to the Github API, but I'd really like to use pyGithub, both to keep the code simple/maintainable (since I already use the library to search for target repos and clone them into /tmp) and because it generally seems like a nice tool I'd like to learn to use well.

Sorry this isn't the most reproducable due to the nature of the problem, but I'll be happy to elaborate on details. Any thoughts?

Update

After implementing this functionality using a requests call I learned thanks to this post that if you make a call using a 'params' argument to pass a json object to the POST request instead of a 'json' argument, you get the same error code. Beginning to suspect a bug, but I'd love to be proven wrong

Answers

Thanks to xjcl, i've figured out why i had this problem too, by i have a little addition, and i hope it will save time to somebody.

The thing is that maybe the repo you are trying to make pull request for does't exist right at the time.

I was writing a little automation tool, which, if repo is modified, creates a new branch, puthes it to GitHub and makes a pull request. The problem was that i was calling GitHub API too fast, right after "git push"

I solved the issue by asking GitHub if the branch exists, and make a pull request only when it does:

import time
import os
import requests
...
    os.popen(f"git push --set-upstream origin {branch_name}")
    os.popen("git checkout main")
    r = requests.get(f"{repo_url}/branches/{branch_name}", headers=headers)
    while r.status_code != 200:
        r = requests.get(f"{repo_url}/branches/{branch_name}", headers=headers)
        print(f'Repo not ready yet: {r.status_code}')
        time.sleep(1)
    payload = {"title": branch_name, "head": branch_name, "base": "main"}
    r = requests.post(f"{repo_url}/pulls", headers=headers,
                      data=json.dumps(payload))
...
Posted on by Anonymous

[{"resource": "PullRequest", "field": "head", "code": "invalid"}]

The error message is trying to communicate that the field/keyword called "head" contains invalid data. Looking at GitHub's REST endpoint documentation:

head: Required. The name of the branch where your changes are implemented. For cross-repository pull requests in the same network, namespace head with a user like this: username:branch.

The way you currently have it set up (head="patch/helm-chart-update", base="master") it goes to the online GitHub repository, looks for branch patch/helm-chart-update there, and tries to prepare a merge to master. Note this will not work if that branch only exists locally (i.e. you haven't done git push) or if you created a fork on GitHub (in which case you need to prefix it with your username as described)

Posted on by xjcl