MaterialDesignInXAML/MaterialDesignInXamlToolkit · error · InvalidOperationException
Did not find repository root
Error message
Did not find repository root
What it means
PathHelper.FindRepoRoot walks upward from the current working directory looking for a directory literally named '.git'; if the loop reaches the filesystem root without finding one it throws InvalidOperationException. This is an environment probe used by the MaterialDesign resource-generation codegen tool to anchor its hard-coded relative output paths (e.g. ..\..\..\..\MaterialDesignColors.Wpf\Themes). It throws purely because the process was started from outside any git checkout, so the tool cannot know where to write generated files.
Solutions
- Run the generator with its working directory set to a folder inside the cloned repository (e.g. the src/MaterialDesignToolkit.ResourceGeneration project folder), not from /tmp, ~, or the bin/ output directory.
- Confirm a real .git directory exists in an ancestor of the working directory with 'git rev-parse --git-dir'; if that prints a path, .git is present.
- If you intentionally lack .git (archive build), make FindRepoRoot accept an override such as the MATERIALDESIGN_REPO_ROOT env var, or a '.repo-root' marker file, before falling back to the throw.
- If you are in a git worktree (where .git is a file), change the probe to also accept a .git file, or use LibGit2Sharp/Native git to resolve the root instead of Directory.Exists.
- Wrap the access to PathHelper.RepositoryRoot so the InvalidOperationException is caught and rethrown with the offending start path for faster diagnosis.
Example fix
// before
private static string FindRepoRoot()
{
for (string? currentDirectory = Path.GetFullPath(".");
!string.IsNullOrEmpty(Path.GetDirectoryName(currentDirectory));
currentDirectory = Path.GetDirectoryName(currentDirectory))
{
if (Directory.Exists(Path.Combine(currentDirectory!, ".git")))
return currentDirectory!;
}
throw new InvalidOperationException("Did not find repository root");
}
// after
private static string FindRepoRoot()
{
var fromEnv = Environment.GetEnvironmentVariable("MATERIALDESIGN_REPO_ROOT");
if (!string.IsNullOrWhiteSpace(fromEnv) && Directory.Exists(fromEnv))
return Path.GetFullPath(fromEnv);
for (string? currentDirectory = Path.GetFullPath(".");
!string.IsNullOrEmpty(Path.GetDirectoryName(currentDirectory));
currentDirectory = Path.GetDirectoryName(currentDirectory))
{
var git = Path.Combine(currentDirectory!, ".git");
// accept directory, git-worktree pointer file, or a marker file for archive builds
if (Directory.Exists(git) || File.Exists(git) ||
File.Exists(Path.Combine(currentDirectory!, ".repo-root")))
return currentDirectory!;
}
throw new InvalidOperationException(
$"Did not find repository root starting from '{Path.GetFullPath(".")}'. " +
"Run from inside the repo checkout or set MATERIALDESIGN_REPO_ROOT.");
} Defensive patterns
Strategy: validation
Validate before calling
string cwd = Path.GetFullPath(".");
bool foundGit = false;
for (string? d = cwd; !string.IsNullOrEmpty(Path.GetDirectoryName(d)); d = Path.GetDirectoryName(d))
{
if (Directory.Exists(Path.Combine(d!, ".git")) || File.Exists(Path.Combine(d!, ".git")))
{
foundGit = true;
break;
}
}
if (!foundGit)
throw new InvalidOperationException(
$"Not running inside a git checkout (cwd={cwd}). cd into the repo or set MATERIALDESIGN_REPO_ROOT."); Type guard
// predicate a caller can check before touching PathHelper.RepositoryRoot
static bool IsInsideRepo(string path) =>
EnumerateAncestors(Path.GetFullPath(path)).Any(d =>
Directory.Exists(Path.Combine(d, ".git")) || File.Exists(Path.Combine(d, ".git")));
static IEnumerable<string> EnumerateAncestors(string dir)
{
for (string? d = dir; !string.IsNullOrEmpty(Path.GetDirectoryName(d)); d = Path.GetDirectoryName(d))
yield return d!;
} Try / catch
try
{
var root = PathHelper.RepositoryRoot;
}
catch (InvalidOperationException ex) when (ex.Message.Contains("repository root"))
{
// report cwd + hint rather than letting the generic throw propagate
throw new InvalidOperationException(
$"{ex.Message} (search started from '{Path.GetFullPath(".")}')", ex);
} Prevention
- Always run dotnet run on the ResourceGeneration project from within the cloned repository tree, never from /tmp, ~, or the bin folder.
- Document the required working directory in the project README so CI/run scripts set it explicitly.
- Add a launchSettings.json with a workingDirectory pointing at the project folder so IDE runs anchor correctly.
- For archive/ZIP builds that lack .git, ship a .repo-root marker file or accept a MATERIALDESIGN_REPO_ROOT env override.
When it happens
Trigger: Running the ResourceGeneration console app with a working directory that is not inside the repository tree, running it from a source tarball/zip export that omits the .git folder, or running it under CI that does a shallow/git-archive checkout without a .git directory. The check is Directory.Exists(<dir>/.git), so a worktree whose .git is a file (git worktree) instead of a directory will also fail this test.
Common situations: Running dotnet run on the generator from the wrong folder; copying the source tree without the .git metadata; building in a sandbox/container where the source was rsync'd without hidden dirs; using 'git archive' or downloading the GitHub ZIP (neither includes .git); switching to a git worktree where .git is a pointer file rather than a folder.
Related errors
- The attribute 'class' was not found
- The input document does not contain a root
- Unable to map foreground color from class
AI-assisted analysis of MaterialDesignInXAML/MaterialDesignInXamlToolkit@98edec3a0b (2026-08-13).
Data as JSON: /api/errors/d6b7f209f1c13439.
Report an issue: GitHub.
Appendix: source
Thrown at src/MaterialDesignToolkit.ResourceGeneration/PathHelper.cs:20
public static class PathHelper
{
private static readonly Lazy<string> _repoRoot = new(FindRepoRoot);
public static string RepositoryRoot => _repoRoot.Value;
private static string FindRepoRoot()
{
for (string? currentDirectory = Path.GetFullPath(".");
!string.IsNullOrEmpty(Path.GetDirectoryName(currentDirectory));
currentDirectory = Path.GetDirectoryName(currentDirectory))
{
if (Directory.Exists(Path.Combine(currentDirectory!, ".git")))
{
return currentDirectory!;
}
}
throw new InvalidOperationException("Did not find repository root");
}
}
View on GitHub (pinned to 98edec3a0b)