You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Backups of a repository fail outright when a remote answers with a Git wire protocol v2 advertisement, because go-git v5 has no protocol v2 support — it never requests v2, and its ref-advertisement decoder only understands the v0/v1 format.
Confirmed cause of a real sync failure (see Reproduction). It is an upstream go-git limitation, and on some hosts the URL form decides whether it is triggered.
Reproduction
Two things had to be true for the observed failure: the remote serves v2, and it does so for the URL form being used.
Against git.eden-emu.dev/eden-emu/eden, the URL form decides the protocol version:
Both return 200 OK with application/x-git-upload-pack-advertisement and no redirect, so this is routing, not an error page — a nonexistent repository on the same host answers 401. Repeated 4×, each form was deterministic at the time of measurement.
The example host has since changed: it now answers the bare path with v0/v1 as well, and both forms return the same 2.5 MB advertisement, so the live trigger can no longer be reproduced. The failure below was captured while it could be, and is simulated in-process by the tests in #31.
Reproduced with the pinned go-git v5.19.2, cloning each form:
suffix-less: clone error=pkt-line 3: cannot read hash, pkt-line too short (version 2) elapsed=102ms
suffixed: clone error=<nil> elapsed=2m23s
That is the failure reported in the sync logs as:
level=ERROR msg="URL repository sync failed." repository=https://git.eden-emu.dev/eden-emu/eden
error="pkt-line 3: cannot read hash, pkt-line too short (version 2)"
pkt-line 3 is the version 2 line: line 1 is the service announcement, line 2 the flush packet, line 3 the version announcement that the v0/v1 decoder tries to read as a ref.
This host is unusual, not representative: on GitHub and Codeberg the suffixed and suffix-less forms both answer v0/v1. Nothing in this codebase sends Git-Protocol, and the host answers v0/v1 on the suffixed path to an anonymous request, so a client cannot influence the suffix-less path's answer.
Evidence that go-git v5 lacks v2
In the pinned go-git v5.19.2 source:
No internal/transport package at all (0 entries in the v5.19.2 tag tree); it exists on main alongside internal/transport/v2.go.
Its HTTP transport sets exactly one request header — Content-Type — so it never asks for v2.
The error string is from plumbing/protocol/packp/advrefs_decode.go, which requires 40 hex characters of hash:
iflen(p.line) <hashSize {
p.error("cannot read hash, pkt-line too short")
}
No fixed release exists on the v5 line: v5.19.2 (2026-07-29) is the newest v5 tag. The v2 client work landed on main (go-git#2237, merged 2026-07-06), which is the v6 line; v6 exists only as alphas, with no stable release. Upstream issue: go-git#1795. Unverified but relevant: that issue reports v6 returning unsupported protocol version, which would mean a naive v5→v6 bump does not fix this either.
Impact
A repository whose remote serves v2 on the form being requested cannot be backed up at all — the clone fails before any snapshot is written, so it is a loud failure, not a silent gap. It affects self-hosted forges whose routing serves v2 on one path form (git.eden-emu.dev above), and any future migration to go-git v6, which defaults to v2.
Options
Immediate, per repository: use the URL form the host serves v1 on. For the example above, configuring https://git.eden-emu.dev/eden-emu/eden.git fixes it today with no code change.
Detect and retry with the other form (implemented in fix(git): retry the other URL form when a host answers with protocol v2 #31). When a sync fails with a v2 advertisement, retry once against the same repository at the other URL form — .git appended, or removed. This turns a hard failure into a working backup without depending on how the URL was written, and it only runs on a failure this client cannot otherwise recover from. The appended form is what the example host serves v1 on, and the removed form covers the mirror-image case.
Report it clearly. The current error names neither the protocol nor the cause. Recognising this failure shape and reporting "the remote serves Git protocol v2, which this client does not support" would turn an opaque parse error into an actionable one.
Wait for a stable v6 release and migrate, then verify such a host against it.
Server-side, if it is under your control: serve v0/v1 on the suffix-less path as well, matching GitHub and Codeberg. This is a server routing quirk, not something the client can request away.
Acceptance
A repository whose host serves v2 on one URL form can be mirrored (option 2, in review)
The failure is reported with the protocol version and the reason, instead of pkt-line N: cannot read hash, pkt-line too short
Summary
Backups of a repository fail outright when a remote answers with a Git wire protocol v2 advertisement, because go-git v5 has no protocol v2 support — it never requests v2, and its ref-advertisement decoder only understands the v0/v1 format.
Confirmed cause of a real sync failure (see Reproduction). It is an upstream go-git limitation, and on some hosts the URL form decides whether it is triggered.
Reproduction
Two things had to be true for the observed failure: the remote serves v2, and it does so for the URL form being used.
Against
git.eden-emu.dev/eden-emu/eden, the URL form decides the protocol version:.../eden-emu/eden/info/refs?service=git-upload-packpkt-line 3: cannot read hash, pkt-line too short (version 2).../eden-emu/eden.git/info/refs?service=git-upload-packBoth return
200 OKwithapplication/x-git-upload-pack-advertisementand no redirect, so this is routing, not an error page — a nonexistent repository on the same host answers401. Repeated 4×, each form was deterministic at the time of measurement.The example host has since changed: it now answers the bare path with v0/v1 as well, and both forms return the same 2.5 MB advertisement, so the live trigger can no longer be reproduced. The failure below was captured while it could be, and is simulated in-process by the tests in #31.
Reproduced with the pinned
go-git v5.19.2, cloning each form:That is the failure reported in the sync logs as:
pkt-line 3is theversion 2line: line 1 is the service announcement, line 2 the flush packet, line 3 the version announcement that the v0/v1 decoder tries to read as a ref.This host is unusual, not representative: on GitHub and Codeberg the suffixed and suffix-less forms both answer v0/v1. Nothing in this codebase sends
Git-Protocol, and the host answers v0/v1 on the suffixed path to an anonymous request, so a client cannot influence the suffix-less path's answer.Evidence that go-git v5 lacks v2
In the pinned
go-git v5.19.2source:internal/transportpackage at all (0 entries in the v5.19.2 tag tree); it exists onmainalongsideinternal/transport/v2.go.Content-Type— so it never asks for v2.plumbing/protocol/packp/advrefs_decode.go, which requires 40 hex characters of hash:No fixed release exists on the v5 line:
v5.19.2(2026-07-29) is the newest v5 tag. The v2 client work landed onmain(go-git#2237, merged 2026-07-06), which is the v6 line; v6 exists only as alphas, with no stable release. Upstream issue: go-git#1795. Unverified but relevant: that issue reports v6 returningunsupported protocol version, which would mean a naive v5→v6 bump does not fix this either.Impact
A repository whose remote serves v2 on the form being requested cannot be backed up at all — the clone fails before any snapshot is written, so it is a loud failure, not a silent gap. It affects self-hosted forges whose routing serves v2 on one path form (
git.eden-emu.devabove), and any future migration to go-git v6, which defaults to v2.Options
https://git.eden-emu.dev/eden-emu/eden.gitfixes it today with no code change..gitappended, or removed. This turns a hard failure into a working backup without depending on how the URL was written, and it only runs on a failure this client cannot otherwise recover from. The appended form is what the example host serves v1 on, and the removed form covers the mirror-image case.Acceptance
pkt-line N: cannot read hash, pkt-line too shortReferences