{"record":{"id":"d70e92fde103abda","repo":"cli/cli","slug":"ref-q-not-found-as-branch-tag-or-commit-in-s","errorCode":null,"errorMessage":"ref %q not found as branch, tag, or commit in %s/%s","messagePattern":"ref %q not found as branch, tag, or commit in (.+?)/(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/skills/discovery/discovery.go","lineNumber":271,"sourceCode":"\t\treturn resolved, nil\n\t} else if !isNotFound(err) {\n\t\treturn nil, err\n\t}\n\n\tcommitPath, err := safeurl.JoinPath(\"repos\", owner, repo, \"commits\", ref)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar commitResp struct {\n\t\tSHA string `json:\"sha\"`\n\t}\n\tif err := client.REST(host, \"GET\", commitPath.String(), nil, &commitResp); err == nil {\n\t\treturn &ResolvedRef{Ref: commitResp.SHA, SHA: commitResp.SHA}, nil\n\t} else if !isNotFound(err) {\n\t\treturn nil, err\n\t}\n\n\treturn nil, fmt.Errorf(\"ref %q not found as branch, tag, or commit in %s/%s\", ref, owner, repo)\n}\n\n// resolveTagRef looks up a tag by short name and returns a fully qualified ref.\n// For annotated tags, the tag object is dereferenced to obtain the commit SHA.\nfunc resolveTagRef(client *api.Client, host, owner, repo, tag string) (*ResolvedRef, error) {\n\ttagPath, err := safeurl.JoinPath(\"repos\", owner, repo, \"git\", \"ref\", fmt.Sprintf(\"tags/%s\", tag))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar refResp struct {\n\t\tObject struct {\n\t\t\tSHA  string `json:\"sha\"`\n\t\t\tType string `json:\"type\"`\n\t\t} `json:\"object\"`\n\t}\n\tif err := client.REST(host, \"GET\", tagPath.String(), nil, &refResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"tag %q not found in %s/%s: %w\", tag, owner, repo, err)\n\t}","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/cli/cli/blob/0eeec0b92edbe70199f9768522f831d3534f41ad/internal/skills/discovery/discovery.go#L253-L289","documentation":"resolveExplicitRef in internal/skills/discovery tries a short version string first as a branch, then as a tag, and finally as a commit SHA (GET repos/{owner}/{repo}/commits/{ref}). If all three lookups return 404 (and only 404; other HTTP errors propagate earlier), it throws this aggregate \"not found as branch, tag, or commit\" error. It means the ref string simply does not exist in the repository in any of the three forms.","triggerScenarios":"ResolveRef called with a version that is not a branch, not a tag, and not resolvable as a commit: a typo (\"main\" vs \"main\"), a tag that was deleted, a branch on a fork rather than the target repo, or a short SHA too ambiguous for the commits endpoint. The calls made are GET .../git/ref/heads/{ref}, GET .../git/ref/tags/{ref}, then GET .../commits/{ref}, each returning 404.","commonSituations":"User passes --ref vX.Y.Z when the tag is spelled v_X_Y_Z or the release exists only on another repo; the default branch was renamed; the commit SHA was truncated to fewer characters than the API tolerates; the repo is a fork and the ref lives upstream.","solutions":["Verify the ref exists: `gh api repos/OWNER/REPO/git/ref/heads/REF` and `.../git/ref/tags/REF`","Fix typos or casing in the ref string; branch and tag names are case-sensitive","If the ref lives on a fork or another repo, point the owner/repo arguments at that repository","Use a full 40-char SHA or a longer unique prefix when passing commits"],"exampleFix":"// before\nresolved, err := discovery.ResolveRef(client, host, owner, repo, \"v1.2.3\")\n\n// after\nresolved, err := discovery.ResolveRef(client, host, owner, repo, \"v1.2.3\")\nif err != nil {\n\t// check spelling against the repo's actual refs before failing\n\t_ = runGH(\"api\", fmt.Sprintf(\"repos/%s/%s/git/matching-refs/\", owner, repo))\n}","handlingStrategy":"validation","validationCode":"// ValidateRefShape cheap-checks a ref string before any API call.\nfunc ValidateRefShape(ref string) error {\n\tif ref == \"\" || ref == \"latest\" {\n\t\treturn nil // handled specially\n\t}\n\tif strings.ContainsAny(ref, \" ~^:[?*\\\\\") {\n\t\treturn fmt.Errorf(\"ref %q contains invalid characters\", ref)\n\t}\n\treturn nil\n}\n\nif err := ValidateRefShape(version); err != nil {\n\treturn err\n}","typeGuard":null,"tryCatchPattern":"resolved, err := discovery.ResolveRef(client, host, owner, repo, version)\nif err != nil {\n\tvar httpErr *api.HTTPError\n\tif errors.As(err, &httpErr) || strings.Contains(err.Error(), \"not found as branch, tag, or commit\") {\n\t\t// ref genuinely absent: surface actionable hint, do not retry\n\t\treturn fmt.Errorf(\"ref %q not found in %s/%s; check spelling with `gh api repos/%s/%s/git/matching-refs/`\", version, owner, repo, owner, repo)\n\t}\n\treturn err // transport failure: safe to retry\n}","preventionTips":["Verify ref existence once with the matching-refs endpoint before entering a discovery flow","Prefer fully qualified refs (refs/tags/v1.2.3) to skip the ambiguous branch/tag/commit chain","Remember short-name resolution tries branch first: a same-named branch shadows the tag"],"tags":["github-api","ref-resolution","not-found","skills"],"backgroundTag":null,"analyzedSha":"0eeec0b92edbe70199f9768522f831d3534f41ad","analyzedAt":"2026-08-15T12:31:05.478Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}