September 24, 2026
macOS Can't Clone "Dumb" Git Repositories Over HTTP/2
Try the following Git clone with libcurl 8.7.1 (which happens to be the version shipped in macOS 14.6 and newer) and it fails or hangs:
git clone https://software.sslmate.com/src/macosgitbug.gitDisable HTTP/2 and it works:
git clone -c http.version=HTTP/1.1 https://software.sslmate.com/src/macosgitbug.git
The bug is in libcurl 8.7.1's handling of the FAILONERROR option.
FAILONERROR tells libcurl to treat unsuccessful HTTP status codes, such as 404,
as a request failure. When HTTP/2 is used, the bug causes other in-flight requests on the same HTTP/2 connection
to also fail, or even to hang.
The bug was fixed over two years ago in curl 8.8.0, but Apple continues to ship a buggy version, even in last week's
macOS 27 release.
When retrieving a repository over the "dumb" transfer protocol, Git makes certain HTTP requests with the FAILONERROR
option set, notably requests to objects/info/alternates and objects/info/http-alternates,
which list alternate locations where the repository's content can be found.
Most repositories don't have alternate locations, so these files don't exist, and the URLs return 404 errors. When
the buggy version of libcurl is used, this 404 error causes Git's other HTTP requests to also fail, and
Git is unable to clone the repository.
The bug affects not just direct uses of Git, but also go get with GOPROXY=direct
or a module listed in GOPRIVATE, which invoke Git under the hood.
Working around the bug on the client side is easy: just force Git to use HTTP/1.1:
git config --global http.version HTTP/1.1Even better, install Git through MacPorts, since Apple has clearly dropped the ball. (Homebrew won't help - unlike MacPorts, they use the system libcurl.)
But most clients won't know to apply this workaround, and if you host Git repositories with the dumb protocol,
you probably want macOS users to be able to clone your repositories! Fortunately, there's a really easy server-side workaround:
create objects/info/alternates and objects/info/http-alternates as empty files, so they don't return a 404
error anymore. Git treats the empty files the same as it would treat a 404 error, and the libcurl bug isn't triggered.
The bug isn't triggered when the repository supports the "smart" protocol, which is why macOS can clone repositories from GitHub and other popular forges despite them using HTTP/2. But I do not want to use the smart protocol for my repositories: although it has many advantages over the dumb protocol, it requires heavy server-side computation and even a modest load can knock a server over. In contrast, the dumb protocol can be served entirely from static files, which makes a huge difference for withstanding the horde of AI scrapers currently terrorizing the Web. I hope that we will see innovations to the dumb protocol that bring it some of the advantages of the smart protocol while still being served from static files.
Thanks to Romain of the Traefik project for noticing that SSLMate's repos couldn't be cloned on macOS, Sebastiaan van Stijn for asking that this problem be reported upstream instead of silently hacked around in Traefik's go.mod file, and Kangmin Kim for pointing me to the libcurl bug as the root cause. Claude Code proposed the empty file workaround so I didn't have to waste (too much) time on this. Zero thanks to Apple for shipping a two-year-old show-stopping bug in libcurl.
Post a Comment
Your comment will be public. To contact me privately, email me. Please keep your comment polite, on-topic, and comprehensible. Your comment may be held for moderation before being published.
Comments
No comments yet.