CoplayDev/unity-mcp · error · InvalidOperationException
Failed to parse GitHub directory tree response.
Error message
Failed to parse GitHub directory tree response.
What it means
After the Git Trees API call returns 2xx, JsonUtility.FromJson<GitHubTreeResponse> yields null or a response whose tree array is null. This means the body was not the expected GitHub tree JSON even though the HTTP status was success.
Source
Thrown at MCPForUnity/Editor/Setup/SkillSyncService.cs:187
{
return false;
}
repoInfo = new GitHubRepoInfo(owner, repo);
return true;
}
private static RemoteSnapshot FetchRemoteSnapshot(GitHubRepoInfo repoInfo, string branch, string subdir, Action<string> log)
{
using var client = CreateGitHubClient();
var commitSha = FetchBranchHeadCommitSha(client, repoInfo, branch, log);
var treeApiUrl = BuildTreeApiUrl(repoInfo, commitSha);
log?.Invoke($"Fetching remote directory tree at commit {ShortCommit(commitSha)}...");
var json = DownloadString(client, treeApiUrl);
var treeResponse = JsonUtility.FromJson<GitHubTreeResponse>(json);
if (treeResponse == null || treeResponse.tree == null)
{
throw new InvalidOperationException("Failed to parse GitHub directory tree response.");
}
if (treeResponse.truncated)
{
throw new InvalidOperationException(
"GitHub returned a truncated directory tree (incomplete snapshot). " +
"Sync was aborted to prevent accidental deletion of valid local files.");
}
var normalizedSubdir = NormalizeRemotePath(subdir);
var subdirPrefix = string.IsNullOrEmpty(normalizedSubdir) ? string.Empty : $"{normalizedSubdir}/";
var remoteFiles = new Dictionary<string, string>(StringComparer.Ordinal);
foreach (var entry in treeResponse.tree)
{
if (!string.Equals(entry.type, "blob", StringComparison.Ordinal))
{
continue;View on GitHub (pinned to c21bf496bc)
Solutions
- Inspect the sync log or capture the raw response body to see what was actually returned.
- Disable or bypass any intercepting proxy / captive portal.
- Retry; transient cache corruption at an intermediary often clears.
- Verify the GitHub REST API directly with curl from the same machine.
Defensive patterns
Strategy: try-catch
Try / catch
try
{
var snapshot = FetchRemoteSnapshot(repoInfo, branch, subdir, log);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("parse GitHub directory tree"))
{
log?.Invoke($"Tree response was not valid GitHub JSON. Likely a proxy/captive page. Raw body should be inspected.");
throw;
} Prevention
- Run behind a direct connection or a transparent proxy, not an intercepting one.
- Log raw response bodies during diagnosis.
- Validate the response shape before trusting JsonUtility output.
When it happens
Trigger: A transparent proxy or captive portal returns 200 with an HTML login/captive page; the GitHub API response schema changed; the body was truncated mid-stream producing partial JSON that JsonUtility silently nulls out.
Common situations: Corporate proxy intercepts the request and returns a 200 status block page; CI runs behind a MITM that rewrites responses; an upstream CDN cache served a stale/wrong payload.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- GitHub returned a truncated directory tree (incomplete snaps
- Failed to resolve branch head commit SHA for: {branch}
- GitHub request failed: {(int)response.StatusCode} {response.
- OpenClaw config contains non-JSON content and cannot be safe
- Color array must have 3 or 4 elements.
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/ed905d5cf677c68e.
Report an issue: GitHub.