GitHub Quietly Removed merge_commit_sha From Its API. Your Automation Won't Error, It'll Just Be Wrong.

GitHub's REST API version 2026-03-10 removed a field called merge_commit_sha from every pull request response. If your automation reads that field to find out which commit a merged PR landed as, it does not crash. It reads null, or undefined, and keeps going as if nothing happened.

That is the entire problem with this kind of change. There is no outage. No error. No 410. The endpoint still returns a 200 and a perfectly valid JSON object. It just quietly stopped containing a value your code depends on. You find out when a deploy goes to the wrong commit, or a changelog script produces garbage, or a bot comments the wrong SHA, days or weeks later, long after anyone connects it to a GitHub API version bump.

GitHub versions its API by date, and you opt into a version with the X-GitHub-Api-Version header. That is good practice on GitHub's part. But it also means the breaking changes are sitting in the new version waiting for you, and "breaking" here rarely means "throws an error." Most of the time it means "returns something different and says nothing."

The changes that fail without erroring

Read through the 2026-03-10 breaking changes and a pattern jumps out. Almost none of them are the kind that announce themselves. Here are the ones most likely to bite quietly.

merge_commit_sha is gone from pull request responses. This field is removed from PR payloads across every endpoint that returns a pull request, including events, lists, and single PR reads. Anything that keys off the merge commit, such as deployment automation, release tooling, or a bot that tracks what landed where, now reads an absent field. No exception is raised. The value is simply missing.

The singular assignee field is removed from Issues and Pull Requests. It duplicated the assignees array and has been "closing down" for years, but plenty of older integrations still read issue.assignee. Those now read nothing. If your triage bot or your reporting script checks the singular field, it will quietly conclude every issue is unassigned.

has_downloads is removed from Repository responses. Deprecated for over a decade, now actually gone. Any code that reads it gets undefined, and any logic branching on it silently takes the wrong path.

The javascript and typescript values are removed from the languages enum in code scanning setup responses, replaced by a combined javascript-typescript. If your code does an equality check or a switch on that enum, the branch that used to match javascript never fires again. Nothing errors. The behavior just changes.

cvss is deprecated in favor of cvss_severities across the advisory and Dependabot alert APIs. The severity data you were reading moves into a new nested shape. Read the old path and you get null severities, which for a security workflow is a genuinely dangerous kind of silent wrong.

The beta media type quietly reshapes payloads. Its remnants change fields like user into owner and master_branch into default_branch. Same data, renamed keys. Your parser does not throw; it just stops finding the values under the names it knows.

There are more, including some status code changes and a couple of endpoints moving work to the background, but the theme holds: the dangerous ones are the ones that return success while handing you a response that no longer matches what your code was written to read.

Why "we pinned the version" is not the same as "we are safe"

The natural defense is version pinning, and you should absolutely pin the X-GitHub-Api-Version header rather than floating. Pinning buys you time. It does not buy you immunity, for three reasons.

First, the old version does not live forever. GitHub supports a previous version for at least 24 months after a new one ships, which means every pin is a deferral with an expiry, not a permanent decision. The migration is coming; you are choosing when.

Second, pinning protects you from the versioned breaking changes, but not from every behavioral change a provider can make. Not everything a large API does is captured in a neat version boundary changelog. Defaults shift, values that were always present start coming back empty in edge cases, a field that was documented as always populated turns out to be nullable under load. Those do not wait for a version bump.

Third, and most important, the version bump does not fail loudly when you finally take it. The whole point of this article is that these changes return 200. So the day you move from your pinned version to 2026-03-10, your tests pass, your code compiles, the API returns success, and the fields you stopped receiving are exactly the ones you were not testing for, because your tests assert against the contract you think the new version has.

This is contract drift with a version number on it

Strip away the GitHub specifics and this is the same failure mode behind every silent integration break. The live API stops matching the contract your code was written against, while still returning a valid response. Usually that drift happens on the provider's timeline with no warning at all. GitHub is actually being responsible here by putting the changes behind a dated version and documenting them. And it still comes down to the same thing: a 200 that contains less than it used to, and code that keeps running on the gap.

This is API contract drift, and a documented, versioned changelog does not save you from it, because reading the changelog and correctly updating every place in your codebase that touched a removed field are two very different tasks. The changelog tells you merge_commit_sha is gone. It does not tell you about the one deploy script from three years ago that still reads it.

Contract testing catches breaking changes in your own API at build time, but it validates your code against your assumptions about GitHub's response, and your assumptions are exactly what a removed field invalidates. The gap between "the call returned 200" and "the response still contains what I need" is the job of runtime monitoring.

What to actually do

Whether or not you have moved to 2026-03-10 yet, the defense is the same.

Validate the responses you get against a schema at the boundary, so a field that has gone missing fails loudly in your own system instead of flowing through as a null. Assert on the values you actually depend on, not just the status code, because a 200 from GitHub tells you nothing about whether merge_commit_sha or your assignee data is still in the payload. Before you bump the pinned version, diff a real response from the old version against the new one on the same request, because the differences you did not expect are the ones that will hurt. And keep checking on a schedule, because the next version is already being written.

The lesson outlives the field

merge_commit_sha is one field in one version of one API. If your automation never read it, this specific change is not your problem. But the shape of it is everyone's problem, and GitHub is the well behaved case: dated versions, a published changelog, a 24-month support window. Even in the best case, the breaking change is a field that quietly disappears from a successful response, and the failure surfaces downstream, in your system, at the worst possible time. If this is what careful looks like, assume every other provider you depend on is doing the same thing with less warning. The only reliable way to know your integrations still match reality is to check the live responses, not the release notes.

Frequently asked questions

What did GitHub remove in the 2026-03-10 API version?

Among other changes, GitHub's 2026-03-10 REST API version removes the merge_commit_sha field from pull request responses, the singular assignee field from Issues and Pull Requests, the has_downloads property from Repository responses, the javascript and typescript values from the code scanning languages enum (replaced by javascript-typescript), and deprecates the cvss property in favor of cvss_severities on advisory and Dependabot alert endpoints. These are versioned breaking changes you opt into via the X-GitHub-Api-Version header.

Will my integration throw an error when these fields are removed?

Usually not. Removing a response field does not cause the request to fail. The endpoint still returns a 200 with a valid JSON object that simply no longer contains the removed field. Code that reads the missing field gets null or undefined and continues running, which is why these changes tend to surface as wrong behavior downstream rather than as an immediate, obvious failure.

Does pinning the X-GitHub-Api-Version header protect me?

Pinning is good practice and buys you time, but it is not permanent protection. GitHub supports a previous version for at least 24 months after a new version ships, so a pin defers the migration rather than avoiding it. Pinning also does not protect against behavioral changes that fall outside a version boundary, and it does not make the eventual version bump fail loudly, since the breaking changes return successful responses.

How do I catch this kind of silent change?

Validate live API responses against a schema at the boundary so missing or reshaped fields fail loudly in your own system, assert on the specific values you depend on rather than just the status code, and diff old and new responses on the same request before bumping a pinned API version. Because providers keep changing on their own schedule, checking on an ongoing basis is more reliable than reading release notes once.

← All posts