Troubleshooting repository mirroring

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

When mirroring fails, project maintainers can see a link similar to Pull mirroring failed 1 hour ago. on the project details page. Select this link to go directly to the mirroring settings, where GitLab displays an Error badge for the mirrored repository. You can hover your mouse cursor over the badge to display the text of the error:

Error message shown on hover

Received RST_STREAM with error code 2 with GitHub

If you receive this message while mirroring to a GitHub repository:

13:Received RST_STREAM with error code 2

One of these issues might be occurring:

  1. Your GitHub settings might be set to block pushes that expose your email address used in commits. To fix this problem, either:
  2. Your repository exceeds GitHub’s file size limit of 100 MB. To fix this problem, check the file size limit configured for on GitHub, and consider using Git Large File Storage to manage large files.

Deadline Exceeded

When you upgrade GitLab, a change in how usernames are represented means that you must update your mirroring username and password to ensure that %40 characters are replaced with @.

Connection blocked: server only allows public key authentication

The connection between GitLab and the remote repository is blocked. Even if a TCP Check is successful, you must check any networking components in the route from GitLab to the remote server for blockage.

This error can occur when a firewall performs a Deep SSH Inspection on outgoing packets.

Could not read username: terminal prompts disabled

If you receive this error after creating a new project using GitLab CI/CD for external repositories:

  • In Bitbucket Cloud:

    "2:fetch remote: "fatal: could not read Username for 'https://bitbucket.org':
    terminal prompts disabled\n": exit status 128."
    
  • In Bitbucket Server (self-managed):

    "2:fetch remote: "fatal: could not read Username for 'https://lab.example.com':
    terminal prompts disabled\n": exit status 128.
    

Check if the repository owner is specified in the URL of your mirrored repository:

  1. On the left sidebar, select Search or go to and find your project.
  2. Select Settings > Repository.
  3. Expand Mirroring repositories.
  4. If no repository owner is specified, delete and add the URL again in this format, replacing OWNER, ACCOUNTNAME, PATH_TO_REPO, and REPONAME with your values:

    • In Bitbucket Cloud:

      https://OWNER@bitbucket.org/ACCOUNTNAME/REPONAME.git
      
    • In Bitbucket Server (self-managed):

      https://OWNER@lab.example.com/PATH_TO_REPO/REPONAME.git
      

When connecting to the Cloud or self-managed Bitbucket repository for mirroring, the repository owner is required in the string.

Pull mirror is missing LFS files

In some cases, pull mirroring does not transfer LFS files. This issue occurs when:

Pull mirroring is not triggering pipelines

Pipelines might not run for multiple reasons:

The repository is being updated, but neither fails nor succeeds visibly

In rare cases, mirroring slots on Redis can become exhausted, possibly because Sidekiq workers are reaped due to out-of-memory (OoM) events. When this occurs, mirroring jobs start and complete quickly, but they neither fail nor succeed. They also do not leave a clear log. To check for this problem:

  1. Enter the Rails console and check Redis’ mirroring capacity:

    current = Gitlab::Redis::SharedState.with { |redis| redis.scard('MIRROR_PULL_CAPACITY') }.to_i
    maximum = Gitlab::CurrentSettings.mirror_max_capacity
    available = maximum - current
    
  2. If the mirroring capacity is 0 or very low, you can drain all stuck jobs with:

    Gitlab::Redis::SharedState.with { |redis| redis.smembers('MIRROR_PULL_CAPACITY') }.each do |pid|
      Gitlab::Redis::SharedState.with { |redis| redis.srem('MIRROR_PULL_CAPACITY', pid) }
    end
    
  3. After you run the command, the background jobs page should show new mirroring jobs being scheduled, especially when triggered manually.

Invalid URL

If you receive this error while setting up mirroring over SSH, make sure the URL is in a valid format.

Mirroring does not support SCP-like clone URLs in the form of git@gitlab.com:gitlab-org/gitlab.git, with host and project path separated using :. It requires a standard URL that includes the ssh:// protocol, like ssh://git@gitlab.com/gitlab-org/gitlab.git.

Host key verification failed

This error is returned when the target host public SSH key changes. Public SSH keys rarely, if ever, change. If host key verification fails, but you suspect the key is still valid, you can refresh the key’s information.

Prerequisites:

  • You must have at least the Maintainer role for a project.

To resolve the issue:

  1. Verify the host key.
  2. On the left sidebar, select Search or go to and find your project.
  3. Select Settings > Repository.
  4. Expand Mirroring repositories.
  5. To refresh the keys, either:

    • Select Detect host keys for GitLab to fetch the host keys from the server, and display the fingerprints.
    • Select Input host keys manually, and enter the host key into the SSH host key field.
  • Select Mirror repository.

Transfer mirror users and tokens to a single service account

This requires access to the GitLab Rails console.

Use case: If you have multiple users using their own GitHub credentials to set up repository mirroring, mirroring breaks when people leave the company. Use this script to migrate disparate mirroring users and tokens into a single service account:

caution
Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
svc_user = User.find_by(username: 'ourServiceUser')
token = 'githubAccessToken'

Project.where(mirror: true).each do |project|
  import_url = project.import_url

  # The url we want is https://token@project/path.git
  repo_url = if import_url.include?('@')
               # Case 1: The url is something like https://23423432@project/path.git
               import_url.split('@').last
             elsif import_url.include?('//')
               # Case 2: The url is something like https://project/path.git
               import_url.split('//').last
             end

  next unless repo_url

  final_url = "https://#{token}@#{repo_url}"

  project.mirror_user = svc_user
  project.import_url = final_url
  project.username_only_import_url = final_url
  project.save
end

The requested URL returned error: 301

When mirroring using the http:// or https:// protocols, be sure to specify the exact URL to the repository: https://gitlab.example.com/group/project.git

HTTP redirects are not followed and omitting .git can result in a 301 error:

13:fetch remote: "fatal: unable to access 'https://gitlab.com/group/project': The requested URL returned error: 301\n": exit status 128.

Push mirror from GitLab instance to Geo secondary fails

Push mirroring of a GitLab repository using the HTTP or HTTPS protocols fails when the destination is a Geo secondary node due to the proxying of the push request to the Geo primary node, and the following error is displayed:

13:get remote references: create git ls-remote: exit status 128, stderr: "fatal: unable to access 'https://gitlab.example.com/group/destination.git/': The requested URL returned error: 302".

This occurs when a Geo unified URL is configured and the target host name resolves to the secondary node’s IP address.

The error can be avoided by:

  • Configuring the push mirror to use the SSH protocol. However, the repository must not contain any LFS objects, which are always transferred over HTTP or HTTPS and are still redirected.
  • Using a reverse proxy to direct all requests from the source instance to the primary Geo node.
  • Adding a local hosts file entry on the source to force the target host name to resolve to the Geo primary node’s IP address.
  • Configuring a pull mirror on the target instead.

Pull or push mirror fails to update: The project is not mirrored

Pull and push mirrors fail to update when GitLab Silent Mode is enabled. When this happens, the option to allow mirroring on the UI is disabled.

An administrator can check to confirm that GitLab Silent Mode is disabled.

When mirroring fails due to Silent Mode the following are the debug steps:

For example, if Silent Mode is what is impeding your imports, the output is similar to the following:

"id": 1,
"update_status": "finished",
"url": "https://test.git"
"last_error": null,
"last_update_at": null,
"last_update_started_at": "2023-12-12T00:01:02.222Z",
"last_successful_update_at": null

Initial mirroring fails: Unable to pull mirror repo: Unable to get pack index

You might get an error that states something similar to the following:

13:fetch remote: "error: Unable to open local file /var/opt/gitlab/git-data/repositories/+gitaly/tmp/quarantine-[OMITTED].idx.temp.temp\nerror: Unable to get pack index https://git.example.org/ebtables/objects/pack/pack-[OMITTED].idx\nerror: Unable to find fcde2b2edba56bf408601fb721fe9b5c338d10ee under https://git.example.org/ebtables
Cannot obtain needed object fcde2b2edba56bf408601fb721fe9b5c338d10ee
while processing commit 2c26b46b68ffc68ff99b453c1d30413413422d70.
error: fetch failed.\n": exit status 128.

This issue occurs because Gitaly does not support mirroring or importing repositories over the “dumb” HTTP protocol.

To determine if a server is “smart” or “dumb”, use cURL to start a reference discovery for the git-upload-pack service and emulate a Git “smart” client:

$GIT_URL="https://git.example.org/project"
curl --silent --dump-header - "$GIT_URL/info/refs?service=git-upload-pack"\
  -o /dev/null | grep -Ei "$content-type:"
  • A “smart” server reports application/x-git-upload-pack-advertisement in the Content-Type response header.
  • A “dumb” server reports text/plain in the Content-Type response header.

For more information, see the Git documentation on discovering references.

To resolve this, you can do either of the following:

  • Migrate the source repository to a “smart” server.
  • Mirror the repository using the SSH protocol (requires authentication).