Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Jenkins By James Joyner IV · · 10 min read

Jenkins Error: 'hudson.plugins.git.GitException: Command "git fetch --tags --force --progress -- origin" returned status code 128' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix hudson.plugins.git.GitException: Command git fetch returned status code 128 in Jenkins — diagnose auth, refs, shallow clone, LFS, and network causes.

  • #jenkins
  • #ci-cd
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

The Jenkins Git plugin runs git fetch under the hood during the SCM checkout step. When the underlying git process exits non-zero, the plugin wraps the exit code in a GitException and fails the build. Status code 128 is Git’s generic “fatal” exit — the plugin can’t tell you why Git failed, only that it did.

hudson.plugins.git.GitException: Command "git fetch --tags --force --progress -- origin +refs/heads/*:refs/remotes/origin/*" returned status code 128:
stdout:
stderr: fatal: Authentication failed for 'https://git.example.com/team/app.git/'

The real cause is in the stderr: line, not the status code. The most common culprits are authentication, a missing or wrong ref/branch, a stale shallow clone, network/DNS failure, or LFS/submodule fetch problems. Always read the stderr before changing anything.

Symptoms

  • Build fails at the “Checkout SCM” / “Declarative: Checkout SCM” stage before any of your pipeline steps run.
  • Console log shows returned status code 128 with a fatal: message in stderr.
  • Manual git clone from your workstation works, but Jenkins fails — pointing at credentials or the agent environment.
  • Intermittent 128s on large repos, often mentioning shallow, RPC failed, early EOF, or remote end hung up.
  • After a force-push or branch delete, checkout of a previously valid commit/ref starts failing.

Common Root Causes

  • Authentication failurefatal: Authentication failed or could not read Username. The credential is missing, revoked, expired (PAT/deploy key), or the wrong credential ID is bound to the SCM config.
  • Host key verification failure (SSH) — the agent has never trusted the Git host, so SSH aborts. This surfaces as a distinct message; see the related guide.
  • Wrong or deleted ref/branchcouldn't find remote ref or Couldn't find any revision to build. The branch was renamed/deleted, or a pipeline parameter points at a non-existent ref.
  • Broken shallow clone / bad object — a partial or corrupted .git in a reused workspace: fatal: the remote end hung up unexpectedly or did not receive expected object.
  • Network, proxy, or DNS failure — the agent can’t reach the Git host: Could not resolve host, Connection timed out, or a corporate proxy blocking 443.
  • Git LFS not installed / not authenticatedgit-lfs filter-process: git-lfs: command not found or an LFS smudge auth failure during fetch.
  • Submodule fetch failure — the parent fetch succeeds but a submodule URL is unreachable or uses different credentials.
  • HTTP buffer / large object limitsRPC failed; curl 56 or early EOF on very large fetches over HTTPS.

How to diagnose

Start by reading the exact stderr in the Jenkins console log — it names the failure class. Then reproduce and add tracing.

Enable Git trace on the agent to see the full transport-level conversation. In a pipeline, set the environment for the checkout:

pipeline {
  agent any
  environment {
    GIT_TRACE = '1'
    GIT_TRACE_PACKET = '1'
    GIT_CURL_VERBOSE = '1'   // HTTPS transport detail
  }
  stages {
    stage('Checkout') {
      steps { checkout scm }
    }
  }
}

Confirm what Jenkins actually runs. Manage Jenkins → System Log and the build console show the full git fetch command line, including the refspec. Verify the branch/refspec matches a ref that still exists:

# Run on the agent as the Jenkins user, using the same credentials:
git ls-remote --heads --tags https://git.example.com/team/app.git
# SSH remotes — prove the agent can authenticate and the host key is trusted:
ssh -T git@git.example.com

Check the agent’s Git and tooling:

git --version                 # plugin needs a reasonably modern git
git lfs version || echo "LFS not installed"
env | grep -i proxy           # http_proxy / https_proxy / no_proxy
nslookup git.example.com      # DNS resolution from the agent

If it only fails inside a reused workspace, the local .git is likely corrupt — inspect it:

cd /var/jenkins_home/workspace/app
git fsck --full || true
git rev-parse HEAD

Fixes

1. Fix credentials binding

Confirm the SCM configuration references a valid credential ID. In the job or pipeline, bind the correct one explicitly rather than relying on inheritance:

checkout([
  $class: 'GitSCM',
  branches: [[name: '*/main']],
  userRemoteConfigs: [[
    url: 'https://git.example.com/team/app.git',
    credentialsId: '<credentials-id>'   // must exist in Jenkins credential store
  ]]
])

For HTTPS, use a Personal Access Token as the password (many hosts no longer accept account passwords). For SSH, store a valid private key and ensure the matching deploy key is registered on the repo. Rotate expired tokens.

2. Trust the host key (SSH)

If stderr says Host key verification failed, add the host to the agent’s known_hosts or use the Git Host Key Verification strategy in Manage Jenkins → Security → Git Host Key Verification Configuration. Full walkthrough in the related guide below.

3. Force a clean, non-shallow checkout when the workspace is corrupt

Add the CleanBeforeCheckout and CloneOption extensions so a bad workspace is discarded and Git doesn’t choke on a broken shallow history:

checkout([
  $class: 'GitSCM',
  branches: [[name: '*/main']],
  extensions: [
    [$class: 'CleanBeforeCheckout'],
    [$class: 'CloneOption', shallow: false, noTags: false, timeout: 30]
  ],
  userRemoteConfigs: [[url: 'https://git.example.com/team/app.git',
                       credentialsId: '<credentials-id>']]
])

If you need shallow for speed on a big repo, set a sane depth and raise the timeout instead of disabling shallow entirely:

[$class: 'CloneOption', shallow: true, depth: 20, timeout: 30]

4. Point at a ref that exists

If stderr says couldn't find remote ref, correct the branch spec or parameter. Guard parameterized checkouts so a typo fails loudly:

script {
  def exists = sh(returnStatus: true,
    script: "git ls-remote --exit-code --heads origin ${params.BRANCH}") == 0
  if (!exists) { error "Branch '${params.BRANCH}' does not exist on origin" }
}

5. Install and configure Git LFS on the agent

Install git-lfs on every agent that checks out an LFS repo, then let the plugin handle LFS via the GitLFSPull extension:

extensions: [[$class: 'GitLFSPull']]

Verify with git lfs env on the agent. Ensure the LFS endpoint credentials match the Git credentials.

6. Fix network / large-fetch failures

For RPC failed / early EOF on big HTTPS fetches, raise the HTTP post buffer on the agent’s Git config:

git config --global http.postBuffer 524288000   # 500 MB

For proxy environments, set http_proxy/https_proxy/no_proxy in the agent’s environment (Node → Configure → Environment variables) so Git uses the proxy. Confirm DNS and firewall rules allow the agent to reach the Git host on 443/22.

What to watch out for

  • Always read stderr, not the 128. The status code is generic; the fatal line is the real error.
  • Pin Git and git-lfs versions across agents. A checkout that works on one agent and 128s on another is usually a tooling or known_hosts difference.
  • Prefer credential IDs over embedding tokens in URLs — tokens in the SCM URL leak into console logs.
  • Reused workspaces accumulate corruption. Add CleanBeforeCheckout on flaky jobs rather than debugging stale .git state repeatedly.
  • Set an explicit checkout timeout so slow fetches fail with a clear message instead of hanging an executor.
  • Repeated 128s that mention retries may escalate into the maximum-checkout-retry-attempts-reached failure — the underlying cause is the same fetch problem.
Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.