argoproj/argo-workflows · error
failed to create branch %q: %w
Error message
failed to create branch %q: %w
What it means
This error is raised at workflow/artifacts/git/git.go:148 in the empty-remote-repository fallback path. After PlainInit and CreateRemote, the driver creates a local branch named after the artifact's revision (defaulting to 'master') with r.CreateBranch, wired to track origin/master. The wrap means go-git's CreateBranch rejected the branch config — usually because a branch with that name already exists, the name is invalid, or the underlying reference write failed.
Source
Thrown at workflow/artifacts/git/git.go:148
}
r, err := git.PlainClone(path, false, cloneOptions)
if errors.Is(err, transport.ErrEmptyRemoteRepository) {
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)
}
}View on GitHub (pinned to 35bff19146)
Solutions
- Check the wrapped err: 'branch already exists' means leftover state — wipe the artifact path and retry the step.
- If a.Revision is a commit SHA or tag, note that this code only handles the empty-repo case; prefer pointing at a non-empty repo or a branch name.
- Ensure the revision string is a valid git branch name (no '..', no trailing '.lock', no invalid characters).
- Be aware the fallback tracks Merge: plumbing.Master even for non-master branchName; if your empty repo will use 'main', expect follow-up fetch oddities and push an initial commit to avoid this path entirely.
Example fix
// before
if err = r.CreateBranch(&config.Branch{Name: branchName, Remote: git.DefaultRemoteName, Merge: plumbing.Master}); err != nil {
// after: tolerate pre-existing branch from a previous attempt
if err = r.CreateBranch(&config.Branch{Name: branchName, Remote: git.DefaultRemoteName, Merge: plumbing.Master}); err != nil && !errors.Is(err, git.ErrBranchExists) {
return fmt.Errorf("failed to create branch %q: %w", branchName, err)
} Defensive patterns
Strategy: validation
Validate before calling
func validBranchName(name string) error {
if name == "" {
return nil // driver defaults to master
}
if strings.ContainsAny(name, " ~^:?*[\\\\") || strings.HasSuffix(name, ".lock") || strings.Contains(name, "..") {
return fmt.Errorf("%q is not a valid git branch name", name)
}
return nil
}
// call before submitting: validBranchName(wfArtifact.Git.Revision) Type guard
func isBranchExistsErr(err error) bool {
return errors.Is(err, git.ErrBranchExists)
} Try / catch
err := artifactDriver.Load(ctx, artifact, path)
if err != nil && strings.Contains(err.Error(), "failed to create branch") {
if isBranchExistsErr(errors.Unwrap(err)) {
os.RemoveAll(path) // clear stale branch state and retry
err = artifactDriver.Load(ctx, artifact, path)
}
}
if err != nil {
return fmt.Errorf("git artifact load failed: %w", err)
} Prevention
- Set git.revision to a branch name when the repo may be empty; use commit SHAs/tags only for populated repos.
- Validate revision strings are legal git branch names before submitting the workflow.
- Avoid reusing artifact paths across retries; wipe the path on retry.
- Remember the fallback hardcodes master as the merge ref — prefer repos with an initial commit to bypass it.
When it happens
Trigger: r.CreateBranch(&config.Branch{Name: branchName, Remote: git.DefaultRemoteName, Merge: plumbing.Master}) fails when loading a git artifact from an empty repository — duplicate branch name (ErrBranchExists), invalid branch name characters in a.Revision (e.g. a commit SHA or tag containing '/'), or a ref write error.
Common situations: Setting git.revision to a commit SHA or tag on an empty-looking repo — SHAs/tags are not valid branch names here; rerunning into a path that already has the branch; a repo where the default branch is 'main' but the fallback hardcodes Merge: plumbing.Master, causing tracking mismatches on later fetches.
Related errors
- failed to plain init: %w
- failed to create remote %q: %w
- failed to clone %q: %w
- failed to validate fetch %v: %w
- single branch mode without a branch specified
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/8807d41427c02019.
Report an issue: GitHub.