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

  1. Confirm the branch exists: call list_branches on the same owner/repo and match the name exactly (case-sensitive)
  2. Check token permissions — fine-grained PATs need Contents: read and write on the target repo
  3. Trim/validate the branch argument before calling delete_file
  4. 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

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


AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15). Data as JSON: /api/errors/1c60143ae5cac2c5. Report an issue: GitHub.