CoplayDev/unity-mcp · error · InvalidOperationException

GitHub request failed: {(int)response.StatusCode} {response.

Error message

GitHub request failed: {(int)response.StatusCode} {response.ReasonPhrase} ({url})\n{body}

What it means

DownloadString throws when any GitHub REST API call (branches or git/trees) returns a non-success status. The message embeds the numeric status code, reason phrase, the requested URL, and the response body for diagnosis.

Source

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

        internal static HttpClient CreateGitHubClient()
        {
            var client = new HttpClient
            {
                Timeout = TimeSpan.FromSeconds(60)
            };
            client.DefaultRequestHeaders.UserAgent.ParseAdd("UnityMcpSkillSync/1.0");
            client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json");
            return client;
        }

        internal static string DownloadString(HttpClient client, string url)
        {
            using var response = client.GetAsync(url).GetAwaiter().GetResult();
            var body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
            if (!response.IsSuccessStatusCode)
            {
                throw new InvalidOperationException($"GitHub request failed: {(int)response.StatusCode} {response.ReasonPhrase} ({url})\n{body}");
            }

            return body;
        }

        private static byte[] DownloadBytes(HttpClient client, string url)
        {
            using var response = client.GetAsync(url).GetAwaiter().GetResult();
            if (!response.IsSuccessStatusCode)
            {
                var body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                throw new InvalidOperationException($"File download failed: {(int)response.StatusCode} {response.ReasonPhrase} ({url})\n{body}");
            }

            return response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
        }

        internal static string NormalizeRemotePath(string path)

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Read the status code in the message: 403 => rate limit, 404 => wrong identifier, 401 => private repo.
  2. For 403: wait for the rate-limit reset window (check X-RateLimit headers) before retrying.
  3. For 404: verify owner, repo, and branch spellings.
  4. For private repos: the service has no token support, so sync from a public mirror/fork.
Defensive patterns

Strategy: retry

Try / catch

try
{
    var json = SkillSyncService.DownloadString(client, url);
}
catch (InvalidOperationException ex)
{
    if (ex.Message.Contains("403"))
        log?.Invoke("GitHub rate limit hit. Wait for the reset window before retrying.");
    else if (ex.Message.Contains("404"))
        log?.Invoke("GitHub returned 404. Check owner/repo/branch spelling.");
    throw;
}

Prevention

When it happens

Trigger: 403 Forbidden from unauthenticated rate limiting (~60 req/hr per IP); 404 Not Found for a wrong owner/repo/branch/tree; 401 if a private repo is targeted; 5xx during a GitHub outage.

Common situations: Repeated syncs exhausting the unauthenticated rate limit; typo in owner/repo; targeting a private repo (the service sends no auth token); GitHub incident.

Related errors


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