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) |