{"record":{"id":"7fec6d3e1e7a7209","repo":"argoproj/argo-workflows","slug":"failed-to-validate-fetch-v-w","errorCode":null,"errorMessage":"failed to validate fetch %v: %w","messagePattern":"failed to validate fetch (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/git/git.go","lineNumber":161,"sourceCode":"\t\tbranchName := a.Revision\n\t\tif branchName == \"\" {\n\t\t\tbranchName = \"master\"\n\t\t}\n\t\tif err = r.CreateBranch(&config.Branch{Name: branchName, Remote: git.DefaultRemoteName, Merge: plumbing.Master}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create branch %q: %w\", branchName, err)\n\t\t}\n\t\treturn nil\n\t} else if err != nil {\n\t\treturn fmt.Errorf(\"failed to clone %q: %w\", a.Repo, err)\n\t}\n\tif len(a.Fetch) > 0 {\n\t\trefSpecs := make([]config.RefSpec, len(a.Fetch))\n\t\tfor i, spec := range a.Fetch {\n\t\t\trefSpecs[i] = config.RefSpec(spec)\n\t\t}\n\t\topts := &git.FetchOptions{Auth: auth, RefSpecs: refSpecs, Depth: depth, InsecureSkipTLS: g.InsecureSkipTLS}\n\t\tif validateErr := opts.Validate(); validateErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to validate fetch %v: %w\", refSpecs, validateErr)\n\t\t}\n\t\tif err = r.Fetch(opts); isFetchErr(err) {\n\t\t\treturn fmt.Errorf(\"failed to fetch %v: %w\", refSpecs, err)\n\t\t}\n\t}\n\tw, err := r.Worktree()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get work tree: %w\", err)\n\t}\n\n\tif a.Revision != \"\" {\n\t\trefSpecs := []config.RefSpec{\"refs/heads/*:refs/heads/*\"}\n\t\tif a.SingleBranch {\n\t\t\trefSpecs = []config.RefSpec{config.RefSpec(fmt.Sprintf(\"refs/heads/%s:refs/heads/%s\", a.Branch, a.Branch))}\n\t\t}\n\t\topts := &git.FetchOptions{Auth: auth, RefSpecs: refSpecs, InsecureSkipTLS: g.InsecureSkipTLS}\n\t\tif err := opts.Validate(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to validate fetch %v: %w\", refSpecs, err)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/git/git.go#L143-L179","documentation":"This error is raised at workflow/artifacts/git/git.go:161 when the git.FetchOptions built from the artifact's 'fetch' list fail go-git's opts.Validate(). Validation is a pure client-side check on the RefSpec strings (plus required fields like Remote/Force defaults), so this fires before any network I/O. It means one or more refspec strings are malformed or the options struct is inconsistent, not that the remote is broken.","triggerScenarios":"ArtifactDriver.Load builds git.FetchOptions{Auth, RefSpecs, Depth, InsecureSkipTLS} from artifact.git.fetch entries and calls opts.Validate(); validation fails because a refspec string is empty or syntactically invalid (go-git refspecs must look like [+]<src>[:<dst>] with valid wildcards, e.g. 'refs/heads/*:refs/heads/*'), or RefSpecs contain mutually inconsistent patterns.","commonSituations":"Typos in the artifact's fetch list (missing colon, stray spaces, bare '*'); using a plus '+refs/...' with a shallow Depth combination rejected by validation; hand-written wildcard refspecs like 'heads/*' without the refs/ prefix; copy-pasted refspecs from CLI git that go-git parses more strictly.","solutions":["Read the wrapped validateErr — go-git reports which refspec and why (e.g. 'invalid refspec').","Fix each fetch entry to the [+]<src>:<dst> form with full ref paths, e.g. 'refs/heads/main:refs/heads/main' or 'refs/heads/*:refs/heads/*'.","Remove empty or whitespace-only entries from artifact.git.fetch.","If using depth (shallow clone), simplify the fetch refspecs to explicit branch refs and retest.","Validate refspec strings locally with a tiny go-git snippet calling (&config.RefSpec(s)).Validate() before deploying the workflow."],"exampleFix":"// before: malformed refspec fails validation\nfetch:\n  - heads/*\n// after: full, valid refspec\nfetch:\n  - \"refs/heads/*:refs/heads/*\"","handlingStrategy":"validation","validationCode":"var refSpecRe = regexp.MustCompile(`^(\\+)?refs/[^\\s]+(:refs/[^\\s]+)?$`)\n\nfunc validateFetchRefspecs(fetch []string) error {\n\tfor _, spec := range fetch {\n\t\tif strings.TrimSpace(spec) == \"\" {\n\t\t\treturn fmt.Errorf(\"empty fetch refspec\")\n\t\t}\n\t\trs := config.RefSpec(spec)\n\t\tif err := rs.Validate(); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid fetch refspec %q: %w\", spec, err)\n\t\t}\n\t\tif !refSpecRe.MatchString(spec) {\n\t\t\treturn fmt.Errorf(\"fetch refspec %q should look like [+]<src>:<dst> with full refs/ paths\", spec)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":"func isValidRefSpec(s string) bool {\n\trs := config.RefSpec(s)\n\treturn rs.Validate() == nil\n}","tryCatchPattern":"// client-side guard before submitting the workflow\nif err := validateFetchRefspecs(artifact.Git.Fetch); err != nil {\n\treturn fmt.Errorf(\"refusing to submit workflow: %w\", err)\n}\n// at runtime, this error is deterministic: do NOT retry\nif err != nil && strings.Contains(err.Error(), \"failed to validate fetch\") {\n\treturn fmt.Errorf(\"fix artifact.git.fetch refspecs: %w\", err)\n}","preventionTips":["Always write refspecs in full [+]<src>:<dst> form with refs/ prefixes.","Lint fetch entries with go-git's RefSpec.Validate in CI before submitting workflows.","Strip empty/whitespace entries from artifact.git.fetch lists.","Avoid mixing shallow depth with complex wildcard refspecs unless tested."],"tags":["git","go-git","refspec","validation","configuration"],"backgroundTag":"invalid-git-refspec","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}