babalae/better-genshin-impact · error · Exception

仓库结构错误:未找到 repo/ 子目录

Error message

仓库结构错误:未找到 repo/ 子目录

What it means

Thrown by GetRepoSubdirectoryTree when HEAD's tip commit exists but its root tree has no entry named 'repo', or the entry exists but is not a Tree (e.g., it's a file/symlink). The script repo contract requires all script content to live under a top-level 'repo/' directory.

Source

Thrown at BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs:1373

        return Repository.IsValid(repoPath) && !Directory.Exists(Path.Combine(repoPath, "repo"));
    }

    /// <summary>
    /// 获取仓库中 repo/ 子目录的树对象
    /// </summary>
    private Tree GetRepoSubdirectoryTree(Repository repo)
    {
        var commit = repo.Head?.Tip;
        if (commit == null)
        {
            throw new Exception("仓库HEAD未指向任何提交");
        }

        // 脚本内容都在 repo/ 子目录下
        var repoEntry = commit.Tree["repo"];
        if (repoEntry == null || repoEntry.TargetType != TreeEntryTargetType.Tree)
        {
            throw new Exception("仓库结构错误:未找到 repo/ 子目录");
        }

        return (Tree)repoEntry.Target;
    }

    /// <summary>
    /// 从中央仓库读取文件内容
    /// </summary>
    /// <param name="relPath">相对于仓库根目录的路径</param>
    /// <returns>文件内容,如果文件不存在则返回null</returns>
    public string? ReadFileFromCenterRepo(string relPath)
    {
        try
        {
            var repoPath = CenterRepoPath;

            // 判断是否为 Git 仓库
            bool isGitRepo = IsGitRepository(repoPath);

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Verify the repository layout: `git ls-tree HEAD <repoUrl>` — confirm a 'repo' directory exists at the root.
  2. Ensure the correct branch is checked out before calling GetRepoSubdirectoryTree (the repo may have repo/ only on 'release').
  3. If the upstream layout changed, update the hardcoded 'repo' entry name in GetRepoSubdirectoryTree to the new convention, or search recursively for the manifest.
  4. Provide a clearer error listing available top-level entries so users/devs can see what the repo actually contains.

Example fix

// before
var repoEntry = commit.Tree["repo"];
if (repoEntry == null || repoEntry.TargetType != TreeEntryTargetType.Tree)
    throw new Exception("仓库结构错误:未找到 repo/ 子目录");

// after (diagnostic)
var repoEntry = commit.Tree["repo"];
if (repoEntry == null || repoEntry.TargetType != TreeEntryTargetType.Tree)
{
    var available = string.Join(", ", commit.Tree.Select(e => $"{e.Name}({e.TargetType})"));
    throw new InvalidOperationException(
        $"仓库结构错误:未找到 repo/ 子目录。当前顶层条目: {available}");
}
Defensive patterns

Strategy: validation

Validate before calling

var repoEntry = commit.Tree["repo"];
if (repoEntry == null || repoEntry.TargetType != TreeEntryTargetType.Tree)
{
    var avail = string.Join(", ", commit.Tree.Select(e => e.Name));
    throw new InvalidOperationException(
        $"未找到 repo/ 子目录。顶层条目: {avail}");
}

Type guard

static bool HasRepoSubdir(Repository repo) =>
    repo.Head?.Tip?.Tree["repo"] is { TargetType: TreeEntryTargetType.Tree };

Try / catch

catch (Exception ex) when (ex.Message.Contains("repo/"))
{
    _logger.LogError("仓库结构不符合预期,请确认仓库约定:{Msg}", ex.Message);
    Toast.Error($"仓库结构错误,缺少 repo/ 目录。请重新下载或更换仓库。");
}

Prevention

When it happens

Trigger: commit.Tree["repo"] returns null or returns a TreeEntry whose TargetType != TreeEntryTargetType.Tree. Happens when the cloned repository doesn't follow the expected layout, the 'repo' entry is a file rather than a directory, or the wrong commit/branch was checked out.

Common situations: User configured a non-conforming repository as the script source; upstream restructured and moved scripts out of 'repo/'; a shallow clone with Depth=1 fetched a historical commit before 'repo/' existed; wrong branch checked out (e.g., 'main' has no repo/ but 'release' does).

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/67cd7dd57105ac4f. Report an issue: GitHub.