LFS (Large File Storage)
Copia repositories support Git LFS for storing large binary files. Workflows can fetch LFS-tracked files at checkout time by setting lfs: true on the actions/checkout step. However, a long-standing issue in the upstream actions/checkout action causes LFS object downloads to fail with HTTP 400 Bad Request against Copia servers. This page explains the cause and shows how to work around it for both actions/checkout@v5 (and earlier) and actions/checkout@v6.
Symptom
When a workflow runs actions/checkout with lfs: true, the Git fetch and the LFS batch metadata request succeed, but every LFS object download fails. The runner log shows two Authorization headers on the object request:
> GET /<owner>/<repo>.git/info/lfs/objects/<oid> HTTP/1.1
> Host: app.copia.io
> Authorization: Basic * * * * *
> Authorization: Basic * * * * *
< HTTP/2.0 400 Bad RequestCause
actions/checkout configures a host-wide Authorization header (http.<server>/.extraheader in Git config) so that subsequent git commands inherit credentials. This is fine for plain git operations.
When git lfs then talks to the LFS batch endpoint, the Copia server responds with its own per-object Authorization header — a short-lived token scoped to that object. git lfs adds that header to the object download request, but the inherited host-wide header is still in effect, so both end up on the same request. Cloudflare and Copia reject any request with duplicate Authorization headers.
The fix is to make sure the host-wide credential is not in effect when git lfs downloads the object. The mechanism differs between actions/checkout@v5 (and earlier) and actions/checkout@v6 because v6 changed where the credential is stored.
In both versions, the workaround sets lfs: false on the actions/checkout step. This stops the action from running its own (failing) LFS fetch — you do the LFS fetch manually after adjusting credentials.
Resolution for actions/checkout@v5 and Earlier
actions/checkout@v5 and EarlierIn v5 and earlier, the credential lives directly in the repository's local Git config at http.<server_url>/.extraheader. The trick is to move it from the host-wide URL to a more specific URL that matches only the LFS batch endpoint. The batch request still gets the credential (so metadata works), but the object download URL no longer matches the prefix, so only the per-object header from the server is sent.
Resolution for actions/checkout@v6
actions/checkout@v6In v6, the credential is no longer written to the local Git config. It is written to a separate file in $RUNNER_TEMP (named git-credentials-<uuid>.config) and pulled in via includeIf.gitdir: directives. As a result, the v5 workaround above is a silent no-op on v6 — there is no http.<server>/.extraheader entry in the local config to read or rewrite.
Instead, disable credential persistence in actions/checkout (so the credential file is removed before your script runs) and configure credentials yourself via the remote URL using a Personal Access Token.
Last updated
Was this helpful?
