ThreeMammals/Ocelot · error · Exception

No coverage.cobertura.*.xml files found in

Error message

No coverage.cobertura.*.xml files found in {artifactsForUnitTestsDir}

What it means

After unit tests run with the coverlet collector, the build expects at least one 'coverage.cobertura.*.xml' report in the unit-test artifacts directory. If GetFiles finds none, this error aborts the coverage reporting step. It means coverage data was never generated or was written elsewhere.

Solutions

  1. Check the logged 'ArtifactsForUnitTestsDir = ...' path and verify coverage.cobertura*.xml exists there manually.
  2. Ensure the dotnet test invocation includes --collect:"XPlat Code Coverage" and the coverlet.collector package.
  3. Confirm the test run succeeded before the coverage step (fix the earlier failing task first).
  4. Align the artifacts directory used by the test task and the coverage glob.
  5. Verify case-sensitivity of the directory path on Linux CI agents.

Example fix

// before
GetFiles(artifactsForUnitTestsDir.ToString() + "/coverage.cobertura.*.xml");
// after
GetFiles(artifactsForUnitTestsDir.ToString() + "/**/coverage.cobertura*.xml");
Defensive patterns

Strategy: validation

Validate before calling

var coverageFiles = GetFiles(artifactsForUnitTestsDir + "/coverage.cobertura.*.xml");
if (!coverageFiles.Any()) throw new Exception($"No coverage files in {artifactsForUnitTestsDir} — did the test task run with coverlet?");

Try / catch

try { GenerateReport(coverageSummaryFile); }
catch (Exception ex) { Error($"Coverage reporting failed: {ex.Message}"); throw; }

Prevention

When it happens

Trigger: Tests did not actually run or produce coverage (test run skipped/failed earlier); coverlet collector not enabled via --collect:"XPlat Code Coverage"; output path differs from artifactsForUnitTestsDir; glob case/path mismatch.

Common situations: Running coverage task without the test task; coverlet.collector package missing from test projects; coverage output redirected to a custom directory; stale artifacts folder cleaned before the check.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of ThreeMammals/Ocelot@d1f22d9304 (2026-09-12). Data as JSON: /api/errors/7617212afb9aaf73. Report an issue: GitHub.

Appendix: source

Thrown at build.cake:595

							$"--coverlet-exclude \"[Ocelot.Testing]*\"",
				WorkingDirectory = "."
			});
			// Only fail on actual test failures, not on thread exit issues
			if (exitCode != 0 && exitCode != 7)
			{
				throw new Exception($"dotnet test failed with exit code {exitCode}");
			}
			else if (exitCode == 7)
			{
				Warning("Tests passed but background threads didn't exit cleanly (exit code 7). Ignoring.");
			}
		}
		
		Information("ArtifactsForUnitTestsDir = " + artifactsForUnitTestsDir);
		// Find all files matching pattern "coverage.cobertura.*.xml"
		var coverageFiles = GetFiles(artifactsForUnitTestsDir.ToString() + "/coverage.cobertura.*.xml");
		if (!coverageFiles.Any())
			throw new Exception($"No coverage.cobertura.*.xml files found in {artifactsForUnitTestsDir}");
		// Get the first matching file (or order by creation date if needed)
		var coverageSummaryFile = coverageFiles.First();
		Information("CoverageSummaryFile = " + coverageSummaryFile);
		GenerateReport(coverageSummaryFile);
		Information("##############################");
		Information("# Code coverage");
		Information("#=============================");

		// TODO Implement reporting to the Action Run summary as an attachment or artifact
		const string CoverallsRepo = "https://coveralls.io/github/ThreeMammals/Ocelot";
		Information($"# There is dedicated Coveralls step of GH Action workflows. So, we won't publish the coverage report to coveralls.io");

		// Apply code coverage threshold
		const double MinCodeCoverage = 0.93D; // consider definition of an env var in GitHub Environment vars
		var lineCoverage = XmlPeek(coverageSummaryFile, "//coverage/@line-rate");
		var branchCoverage = XmlPeek(coverageSummaryFile, "//coverage/@branch-rate");
		Information("# Line Coverage: " + lineCoverage);
		Information("# Branch Coverage: " + branchCoverage);

View on GitHub (pinned to d1f22d9304)