CoplayDev/unity-mcp · error · InvalidOperationException

Failed to resolve branch head commit SHA for: {branch}

Error message

Failed to resolve branch head commit SHA for: {branch}

What it means

FetchBranchHeadCommitSha parses the Branches API response and expects branchResponse.commit.sha. If that field is null/empty/whitespace after parsing a 2xx response, the SHA cannot be resolved and the sync cannot proceed.

Source

Thrown at MCPForUnity/Editor/Setup/SkillSyncService.cs:255

            if (remoteFiles.Count == 0)
            {
                throw new InvalidOperationException($"Remote directory not found: {normalizedSubdir}");
            }

            log?.Invoke($"Remote file count: {remoteFiles.Count}");
            return new RemoteSnapshot(commitSha, normalizedSubdir, remoteFiles);
        }

        private static string FetchBranchHeadCommitSha(HttpClient client, GitHubRepoInfo repoInfo, string branch, Action<string> log)
        {
            var branchApiUrl = BuildBranchApiUrl(repoInfo, branch);
            log?.Invoke($"Fetching branch head commit...");
            var branchJson = DownloadString(client, branchApiUrl);
            var branchResponse = JsonUtility.FromJson<GitHubBranchResponse>(branchJson);
            var commitSha = branchResponse?.commit?.sha?.Trim();
            if (string.IsNullOrWhiteSpace(commitSha))
            {
                throw new InvalidOperationException($"Failed to resolve branch head commit SHA for: {branch}");
            }

            return commitSha;
        }

        private static string BuildBranchApiUrl(GitHubRepoInfo repoInfo, string branch)
        {
            return $"https://api.github.com/repos/{Uri.EscapeDataString(repoInfo.Owner)}/{Uri.EscapeDataString(repoInfo.Repo)}/branches/{Uri.EscapeDataString(branch)}";
        }

        private static string BuildTreeApiUrl(GitHubRepoInfo repoInfo, string reference)
        {
            return $"https://api.github.com/repos/{Uri.EscapeDataString(repoInfo.Owner)}/{Uri.EscapeDataString(repoInfo.Repo)}/git/trees/{Uri.EscapeDataString(reference)}?recursive=1";
        }

        private static string BuildRawFileUrl(GitHubRepoInfo repoInfo, string commitSha, string remoteFilePath)
        {
            var encodedPath = string.Join("/",

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Verify the branch name is correct (case-sensitive on some repos).
  2. Capture and inspect the raw Branches API response body.
  3. Retry in case of a transient intermediary issue.
  4. Confirm there is no proxy rewriting the JSON payload.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    var sha = FetchBranchHeadCommitSha(client, repoInfo, branch, log);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("branch head commit SHA"))
{
    log?.Invoke($"Could not resolve SHA for branch '{branch}'. Verify the branch exists and the API response is intact.");
    throw;
}

Prevention

When it happens

Trigger: The branch API returned 2xx but with a schema that did not deserialize commit.sha (API change, proxy-rewritten body); the response parsed into a default object because JsonUtility could not map the fields.

Common situations: GitHub API schema drift; an intermediary returned a 200 with a different JSON shape; extremely rare compared to the 404 path which surfaces as error 67.

Related errors


AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13). Data as JSON: /api/errors/9e07e8d79f5331e0. Report an issue: GitHub.