argoproj/argo-workflows · error

failed to clone %q: %w

Error message

failed to clone %q: %w

What it means

This is the generic clone-failure wrap at workflow/artifacts/git/git.go:152. When git.PlainClone fails with anything other than transport.ErrEmptyRemoteRepository, Load returns 'failed to clone %q' wrapping the underlying go-git error. The real cause is always in the wrapped error: bad URL, auth failure, unknown revision/branch, TLS problems, or network errors.

Source

Thrown at workflow/artifacts/git/git.go:152

		logging.RequireLoggerFromContext(ctx).Info(ctx, "Cloned an empty repository")
		var initErr error
		r, initErr = git.PlainInit(path, false)
		if initErr != nil {
			return fmt.Errorf("failed to plain init: %w", initErr)
		}
		if _, remoteErr := r.CreateRemote(&config.RemoteConfig{Name: git.DefaultRemoteName, URLs: []string{a.Repo}}); remoteErr != nil {
			return fmt.Errorf("failed to create remote %q: %w", a.Repo, remoteErr)
		}
		branchName := a.Revision
		if branchName == "" {
			branchName = "master"
		}
		if err = r.CreateBranch(&config.Branch{Name: branchName, Remote: git.DefaultRemoteName, Merge: plumbing.Master}); err != nil {
			return fmt.Errorf("failed to create branch %q: %w", branchName, err)
		}
		return nil
	} else if err != nil {
		return fmt.Errorf("failed to clone %q: %w", a.Repo, err)
	}
	if len(a.Fetch) > 0 {
		refSpecs := make([]config.RefSpec, len(a.Fetch))
		for i, spec := range a.Fetch {
			refSpecs[i] = config.RefSpec(spec)
		}
		opts := &git.FetchOptions{Auth: auth, RefSpecs: refSpecs, Depth: depth, InsecureSkipTLS: g.InsecureSkipTLS}
		if validateErr := opts.Validate(); validateErr != nil {
			return fmt.Errorf("failed to validate fetch %v: %w", refSpecs, validateErr)
		}
		if err = r.Fetch(opts); isFetchErr(err) {
			return fmt.Errorf("failed to fetch %v: %w", refSpecs, err)
		}
	}
	w, err := r.Worktree()
	if err != nil {
		return fmt.Errorf("failed to get work tree: %w", err)
	}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the wrapped inner error in the message — it names the actual cause (auth, not-found, TLS, network) and fixes differ per cause.
  2. For auth errors: verify the git secret (ssh-key format includes the 'PRIVATE KEY' header, correct username for HTTPS tokens) and that the secret is referenced correctly in the artifact.
  3. For not-found errors: test the URL with 'git ls-remote <url>' from an environment with the same credentials; fix typos or org renames.
  4. For TLS errors: set insecureSkipTLS: true (non-prod) or mount the CA cert into the executor and configure it.
  5. For Azure DevOps: confirm the workaround context — go-git cannot clone Azure DevOps repos while multi_ack capabilities are unsupported; keep the repo URL containing dev.azure.com so the driver applies its capability workaround.

Example fix

// before: artifact failing to authenticate
- git:
    repo: https://github.com/my-org/private-repo.git
// after: supply credentials via secret
- git:
    repo: https://github.com/my-org/private-repo.git
    usernameSecret:
      name: github-creds
      key: username
    passwordSecret:
      name: github-creds
      key: token
Defensive patterns

Strategy: try-catch

Validate before calling

func precheckRepoReachable(repoURL string, creds *GitCreds) error {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	a := &wfv1.Artifact{ArtifactPaths: nil, Git: &wfv1.GitArtifact{Repo: repoURL}}
	_ = a
	run := exec.CommandContext(ctx, "git", "ls-remote", repoURL)
	if creds != nil {
		run.Env = append(os.Environ(), creds.Env()...)
	}
	out, err := run.CombinedOutput()
	if err != nil {
		return fmt.Errorf("repo %s unreachable: %v: %s", repoURL, err, out)
	}
	return nil
}

Type guard

func isAuthErr(err error) bool {
	var ar *transport.AuthError
	return errors.As(err, &ar)
}
func isNotFoundErr(err error) bool {
	return errors.Is(err, transport.ErrRepositoryNotFound)
}

Try / catch

err := artifactDriver.Load(ctx, artifact, path)
if err != nil && strings.Contains(err.Error(), "failed to clone") {
	inner := errors.Unwrap(errors.Unwrap(err))
	switch {
	case isAuthErr(inner):
		return fmt.Errorf("check git credentials/secret: %w", err)
	case isNotFoundErr(inner):
		return fmt.Errorf("verify repo URL exists and is accessible: %w", err)
	default:
		// transient network issue: bounded retry
		for i := 0; i < 3; i++ {
			time.Sleep(time.Duration(1<<i) * time.Second)
			if retryErr := artifactDriver.Load(ctx, artifact, path); retryErr == nil {
				return nil
			}
		}
		return err
	}
}

Prevention

When it happens

Trigger: git.PlainClone(path, false, cloneOptions) in ArtifactDriver.Load fails for any non-empty-repo reason: unreachable host, authentication rejected (SSH key/HTTPS token), repository not found, TLS certificate verification failure, or the target path already containing a non-empty git repository.

Common situations: Wrong or renamed repo URL in the workflow spec; missing or expired git credentials (sshPrivateKey secret, HTTPS token); private repos without credentials; self-signed/ corporate CA certificates without insecureSkipTLS or the CA mounted; Azure DevOps repos hitting go-git capability issues; shallow depth=0 combined with unsupported refs.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/ad1f87e7c4b4ea58. Report an issue: GitHub.