Every call of GitHub's API asks for its version¶
- Status: accepted
- Date: 2026-11-08
Context¶
GitHub versions its REST API by date. A request names its version in the header X-GitHub-Api-Version. The GitHub CLI sends 2022-11-28 today without being asked, but that default is the CLI's, not the blueprint's: a newer GitHub CLI on the runner image can move it, and an older one may send no version at all, so that GitHub answers with the version it serves by default. On either day a request gets other answers, with no change in the repository that sends it, and a bot finds out in a failed run. The blueprint pins the version itself.
The issue assistant asks for 2022-11-28 on every call (Dennis-Otto/issue-assistant#239). The blueprint didn't: its workflows, which every repository gets, called gh api 110 times in 18 files without the header, and so did the Python of the blueprint, at the runners of Api in blueprint/github.py, which most of it calls, and at three places that start gh api themselves (#690).
Options¶
- The header in the
env:of each step that runsgh api, as the issue assistant does for the two workflows of its own: 40 steps, and a new step that calls the API lacks it until someone adds it. - The header in the
env:of each workflow that callsgh api, besideGH_TELEMETRY, which every workflow that runs the GitHub CLI already sets there (decision 0080): one line in each of the 18 files, and every step of the workflow has it. - A wrapper of
gh, such as a function or an alias ofgh alias setin each step, which adds the header: the GitHub CLI has no setting for a header of every call, and a wrapper hides what a step sends from someone who reads it. - Nothing: the GitHub CLI keeps sending
2022-11-28until a version of it, or GitHub, changes the default.
Decision¶
Option 2.
- Workflows. Each workflow that calls
gh apisetsAPI_VERSION_HEADER: "X-GitHub-Api-Version: 2022-11-28"in itsenv:, and each call asks right aftergh api:gh api --header "$API_VERSION_HEADER" …, GraphQL as well, so that one rule holds for every call. The value is no secret, and an action of a step that reads it learns nothing. - Python.
blueprint/github.pyholdsAPI_VERSIONandAPI_VERSION_HEADER.gh_command()puts the header at the end of each call ofgh api, and both runners ofApistart gh through it;blueprint/bootstrap.py,blueprint/app.pyanddashboard.pyend their own calls ofgh apiwith it. - Tests.
tests/test_template.pyfails on a call ofgh apiwithout the header, or in a workflow whose environment doesn't set it toAPI_VERSION_HEADERofblueprint/github.py, in the blueprint and in each kind of project.tests/test_api_version.pyreads the Python of the blueprint withastand fails on a call ofgh apithat doesn't end with the header, and on a second place that starts gh with any arguments. The gh of the tests of the steps, and the simulated shells ofblueprint.py createand of the release app, refuse a call ofgh apiwithout the version. - The copies of the issue assistant's workflows stay as the issue assistant makes them: it keeps them, and its own tests check its calls.
Consequences¶
A newer default of the GitHub CLI or of GitHub changes no answer of a bot. The move to a newer version is one change: API_VERSION in blueprint/github.py and the line in each workflow, which the test keeps equal, after a read of the breaking changes of that version. The calls are longer by the header. The workflows that a project adds of its own aren't the blueprint's to check: such a workflow asks for the version the same way.