Skip to content

Troubleshooting

Every row below is something that actually happened while building this template -- the exact message (or, where it was a silent failure, what you would see instead) and the fix that was applied to the repository or that you apply yourself.

Symptom / message Cause Fix
net7.0 project builds, but .NET 7.0 is out of support warnings, or it only works because an unrelated old runtime happens to be installed Target framework not updated since .NET 7 went out of support (May 2024) Fixed in this template: every .csproj targets net10.0 via Directory.Build.props, pinned in global.json. If you see this on your own fork, re-run 4-install-tools and check global.json.
dotnet publish on the solution prints warning NETSDK1194: The "--output" option isn't supported when building a solution... and silently mixes CalculatorLibrary, CalculatorApp and CalculatorLibrary.Tests output into one folder Publishing a .sln with -o merges every project's output into the same directory -- not a hard error in current SDKs, so it is easy to miss until binaries behave strangely Publish the app project, not the solution: dotnet publish CalculatorApp\CalculatorApp.csproj -c Release -r win-x64 -o publish\windows (this is what 10-release does).
reports/<platform>/_raw/doccoverage/lcov.info is created but is 0 bytes, no error printed, genhtml/ReportGenerator then show "no data" coverxygen's --prefix is a filter (keep only files under this path), and %currentDir% was never set in the original script -- so the filter matched nothing 7-build-all sets currentDir/currentDirFwd at the top and passes --prefix "%currentDirFwd%/".
The line above, fixed to set currentDir, still produces an empty lcov.info on Windows Doxygen records file paths internally with forward slashes even on Windows; --prefix compared against a backslash path never matches Use a forward-slash prefix: set "currentDirFwd=%currentDir:\=/%", then --prefix "%currentDirFwd%/" (already done in 7-build-all.bat; irrelevant on Linux, where paths are forward-slash natively).
'genhtml' is not recognized as an internal or external command in a .bat script, even though where genhtml finds it and running it directly in Git Bash works genhtml (from the Windows lcov Chocolatey package) is a Perl script with no .exe/.bat extension; cmd.exe cannot execute an extensionless file directly (unlike a POSIX shell, which reads the shebang) Invoke it as perl "<path-to-genhtml>", not bare genhtml -- 7-build-all.bat resolves the path via where genhtml (falling back to the default Chocolatey path) and always runs it through perl.
python -m coverxygen fails with ModuleNotFoundError: No module named 'coverxygen' even after pip install coverxygen succeeded, and the documentation-coverage report is silently empty On a machine with several Python installs, plain python on PATH can resolve to an unrelated interpreter (e.g. a vector-graphics editor's bundled python.exe, found earlier on PATH than a real Python) that never had coverxygen installed into it Use an explicit interpreter: py -3.12 -m coverxygen ... (what 4-install-tools.bat/7-build-all.bat do); on WSL/Linux use python3 explicitly.
.gitignore, the .csproj or coverage numbers change on every single build for no code reason The old script ran dotnet add package coverlet.msbuild on every build, mutating CalculatorLibrary.Tests.csproj and re-resolving an unpinned version each time Removed: coverage is collected with --collect:"XPlat Code Coverage" (the VSTest collector, from the already-referenced coverlet.collector package) -- coverlet.msbuild was never actually used by that collection method and is not referenced at all now. Package versions are pinned directly in the .csproj; never run dotnet add package from a build script.
error CS0182: An attribute argument must be a constant expression... on an xUnit [InlineData(new string[] { ... })] You cannot pass an array literal straight into [InlineData] (ambiguous with the attribute's own params object[]) Use [MemberData(nameof(SomeMethod))] with a static IEnumerable<object[]> instead (see CalculatorCliTests.WrongArgumentCounts).
A test asserting int.MinValue / -1 == int.MinValue throws System.OverflowException instead of returning a value, even though the code never uses a checked block This one division cannot be represented as a positive int (its magnitude is one larger than int.MaxValue); .NET always raises OverflowException here regardless of checked/unchecked context Test for the exception instead of a return value: Assert.Throws<OverflowException>(() => calc.Divide(int.MinValue, -1)) (see CalculatorTests). This is a real boundary case worth knowing, not a bug to work around.
A .bat script fails with The system cannot find the batch label specified - <label>, even though the label is clearly in the file The file has Unix-style LF-only line endings (e.g. after editing with a non-Windows tool); cmd.exe's GOTO/CALL :label search can fail to find labels in an LF-only file Convert to CRLF (e.g. in Git Bash: sed -i 's/\r$//' file.bat && sed -i 's/$/\r/' file.bat, or in an editor: "Save with line endings: CRLF"). Every .bat in this repository is CRLF; keep it that way.
A .bat script fails with <some word> was unexpected at this time. inside an if (...)/for (...) block A literal ( or ) appears inside that block -- even inside a quoted string, even as a comment -- and confuses cmd.exe's parenthesis-matching scan for the block's boundaries Avoid literal parentheses in any text that lives inside a parenthesized block (rewrite "genhtml (documentation coverage)" as "genhtml - documentation coverage", etc.), or escape them with ^(/^) outside of quotes.
'somescript.bat' is not recognized as an internal or external command, even right after cd /d "%~dp0", even though the file is right there The machine has the environment variable NoDefaultCurrentDirectoryInExePath set (a common hardening setting on managed/lab PCs), which disables cmd.exe's implicit "also search the current directory" fallback for bare filenames Call sibling scripts by full path, not bare filename: call "%~dp0scripts\dotnet-env-windows.bat", not call scripts\dotnet-env-windows.bat -- every script in this repository already does this.
A .bat build step fails, but the script happily continues to the next step and exits with code 0 anyway exit /b 1 inside a subroutine reached via call :label only ends that subroutine (like a return), not the whole script -- the caller must explicitly check the result Always call as call :check "step name" \|\| exit /b 1 (or an equivalent if errorlevel 1 exit /b 1 immediately after), never call :check "..." alone.
A variable that was clearly just set inside an if (...)/for (...) block reads back as empty (or stale) immediately afterward, inside that same block cmd.exe substitutes %var% once, when the block is parsed, not per execution -- a set-then-read of the same variable inside one shared block silently uses the value from before the block started Either enable setlocal enabledelayedexpansion and use !var! for that read, or (what this template prefers where practical) split the set and the read into separate top-level statements so the read happens in its own, freshly-parsed line after the set has already executed.
A robocopy step in a .bat script is treated as failed even though the copy clearly worked robocopy's exit codes 0-7 are all success/informational (1 = files copied, 2 = extra files, ...); only 8+ is a real failure -- a plain if errorlevel 1 after robocopy misfires constantly Check if errorlevel 8 for robocopy specifically, not if errorlevel 1 (see :check_robocopy in 7-build-all.bat).
DocFX prints warning InvalidFileLink / Unable to find file "reports/....html" during docfx build These point at resource files (the copied report HTML folders); DocFX's TOC-link validator only tracks content documents, not resource files, at the point it checks links Benign: the files are still copied and the links still work (confirmed by opening the built site). If instead you see it for a .md file that should be real content, check docfx.json's content globs/excludes.
A brand-new .git\refs\heads\desktop.ini (or similar) appears, and git branch prints warning: ignoring broken ref refs/heads/desktop.ini The repository lives inside a Google Drive-synced folder, and Drive writes its own desktop.ini folder-customization file into .git's internals Harmless; git ignores the broken ref. Do not try to "fix" it by editing .git by hand.
WSL cannot see the repository, or sees it but every file operation is extremely slow, when the clone lives under /mnt/g/My Drive/... Google Drive for desktop is a virtual/cloud filesystem; even mounted into WSL through the G: drive, it is not a real, fully POSIX-compatible filesystem Copy the repository into a normal Linux path first (e.g. ~/vs-net-core-template) and run every .sh script from there -- this is exactly how this template's own .sh scripts were tested (see Install).
choco install astyle sits waiting for a [Y/n] confirmation instead of finishing Some Chocolatey install commands prompt for confirmation unless -y is passed Fixed: every choco install in this template's scripts passes -y. If you add your own, do the same.
A numbered script prints its banner and then just sits there, never returning control to the terminal An old copy of a script called pause (or otherwise waited on console input) Every script in this template avoids blocking on input entirely (no pause). The sample app only reads its arguments, never the console, see From topic to project.
A build step fails with a file-locked/"being used by another process" error, especially right after antivirus updated its definitions Windows Defender (or another AV) briefly locks freshly-written .dll/.exe files while scanning them, racing with the next build step Re-run the script (usually enough); if it happens constantly, add an exclusion for the repository folder and %LocalAppData%\Microsoft\dotnet in your antivirus settings.
A path-related build error mentions a file that clearly exists, on a very deeply nested clone location Windows' classic ~260-character path limit, more likely to bite with a long Google Drive path plus bin/obj plus a long RID/config subfolder Clone closer to a drive root, or enable Windows long-path support (git config --system core.longpaths true plus the Windows 10/11 "Enable Win32 long paths" setting).
Opening site/index.html (or a report) shows a blank page or broken links when opened via a file:// path but works when served over HTTP Rare, but some browsers restrict file:// pages from fetching adjacent JSON (DocFX's search index, for example) Serve it locally instead: 9-open-site.bat/.sh (this is what it does automatically now), dotnet docfx serve site (default http://localhost:8080), or any static file server.
A report page's <iframe> stays blank even though "Open in a new tab" on the same page works The site was opened via a bare file:// path instead of 9-open-site's local server -- see Showing a report inside your site for the full explanation and every other iframe-related problem. Use 9-open-site.bat/.sh and open the printed http://localhost:8080/ URL.
9-open-site.bat/.sh exits with an error instead of serving the site Port 8080 (the default) is already in use by something else on your machine Pass a different port: 9-open-site.bat 8081 / ./9-open-site.sh 8081.
Compress-Archive (in 7-build-all.bat's report-zipping step) fails with a file-in-use error A report's HTML file was still open in a browser/editor while the script re-ran, or antivirus was scanning it mid-write (see the antivirus row above) Close anything that has a file under docs/<report>/ open, then re-run 7-build-all.bat; the step is idempotent.

Still stuck?

Re-read the exact step in Daily workflow or Use this template, and check Which report is which? to make sure you are looking at the right file. | MSB4126: The specified solution configuration "Debug|windows" is invalid | A PLATFORM environment variable is read by MSBuild as the Platform property; a script that exported PLATFORM=windows breaks every build | The scripts use PLATFORM_TOKEN instead; never export a variable named PLATFORM | | mkdocs / ModuleNotFoundError: No module named 'material' | MkDocs Material is not installed for that Python | 4-install-tools-<platform> (or py -3.12 -m pip install --user -r requirements.txt) | | check-links prints broken link(s) | A page links to something missing (typo, or a report folder not copied) | Fix the path it prints; see "Common problems" in Showing an HTML report inside your site | | A report page shows "not built on this machine" | You built on one platform only; the other platform's reports are built there (CI builds both) | Run 7-build-all on that platform, or use the release | | dotnet test cannot find the dll after dotnet build | Build and test used different --artifacts-path values | Use the numbered scripts; they pass build/<platform>-<config> to both | | 9-open-site says port 8080 is in use | Another program listens there | 9-open-site-windows.bat 8081 (or ./9-open-site-linux.sh 8081) |