github/github-mcp-server · error
failed to get branch reference: %w
Error message
failed to get branch reference: %w
What it means
delete_file resolves the branch head via client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch) before constructing the deletion commit; this error wraps any failure of that lookup. Unlike neighboring calls it uses a plain fmt.Errorf rather than ghErrors.NewGitHubAPIErrorResponse, so rate-limit detail and response context are lost. The dominant cause is go-github's ErrorResponse for 404/422 'Reference does not exist' — i.e., the branch is not there.
Source
Thrown at pkg/github/repositories.go:1121
}
message, err := RequiredParam[string](args, "message")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
branch, err := RequiredParam[string](args, "branch")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
client, err := deps.GetClient(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
}
// Get the reference for the branch
ref, resp, err := client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch)
if err != nil {
return nil, nil, fmt.Errorf("failed to get branch reference: %w", err)
}
defer func() { _ = resp.Body.Close() }()
// Get the commit object that the branch points to
baseCommit, resp, err := client.Git.GetCommit(ctx, owner, repo, *ref.Object.SHA)
if err != nil {
return ghErrors.NewGitHubAPIErrorResponse(ctx,
"failed to get base commit",
resp,
err,
), nil, nil
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, fmt.Errorf("failed to read response body: %w", err)View on GitHub (pinned to 0ea1f775a7)
Solutions
- Confirm the branch exists: call list_branches on the same owner/repo and match the name exactly (case-sensitive)
- Check token permissions — fine-grained PATs need Contents: read and write on the target repo
- Trim/validate the branch argument before calling delete_file
- If the ref genuinely exists, retry — transient 5xx from the Git refs endpoint also surfaces here
Example fix
// before
ref, resp, err := client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch)
if err != nil {
return nil, nil, fmt.Errorf("failed to get branch reference: %w", err)
}
// after — validate the name and keep the structured error path
if strings.TrimSpace(branch) == "" || strings.ContainsAny(branch, " ~^:?[\\*") {
return utils.NewToolResultError("invalid branch name"), nil, nil
}
ref, resp, err := client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch)
if err != nil {
return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to get branch reference", resp, err), nil, nil
} Defensive patterns
Strategy: validation
Validate before calling
// Verify the branch exists before calling delete_file
_, _, err := client.Git.GetRef(ctx, owner, repo, "refs/heads/"+branch)
if err != nil {
var ghErr *github.ErrorResponse
if errors.As(err, &ghErr) && (ghErr.Response.StatusCode == 404 || ghErr.Response.StatusCode == 422) {
return fmt.Errorf("branch %q does not exist in %s/%s", branch, owner, repo)
}
} Type guard
func branchExists(err error) bool {
var ghErr *github.ErrorResponse
return !(errors.As(err, &ghErr) && ghErr.Response != nil &&
(ghErr.Response.StatusCode == 404 || ghErr.Response.StatusCode == 422))
} Try / catch
if err != nil {
var ghErr *github.ErrorResponse
if errors.As(err, &ghErr) {
switch ghErr.Response.StatusCode {
case 404, 422:
// branch missing: fix the name, do not retry
case 403:
// token lacks access: fix scopes
default:
// transient 5xx: retry with backoff
}
}
} Prevention
- Discover the exact branch name with list_branches instead of assuming main/master
- Trim and format-check branch arguments before delete_file
- Use fine-grained PATs with Contents: read and write on the target repo
- Remember this path returns a plain wrapped error, not a structured one — parse the message chain for the GitHub ErrorResponse detail
When it happens
Trigger: Branch name typo or main-vs-master mismatch (repo's default branch differs from the argument); token lacks read access to the repo; owner/repo misspelled; branch argument with leading/trailing whitespace making the ref path invalid; empty repository with no refs.
Common situations: Calling delete_file with "branch":"main" on older repos using "master", fine-grained PATs missing Contents read/write, freshly renamed branches, stale cached branch names in automation scripts.
Related errors
- %s: %w
- unexpected status %d: %s
- failed to get base REST URL: %w
- failed to get upload URL: %w
- failed to get issue ID: %w
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/1c60143ae5cac2c5.
Report an issue: GitHub.