theonedev/onedev · error · ExplicitException

Invalid report name

Error message

Invalid report name

What it means

CoverageStats.checkReportName rejects any coverage report name containing ".." because the name is used to build file paths under a report directory; ".." would allow escaping that directory (path traversal). OneDev surfaces this as an ExplicitException with the message "Invalid report name".

Source

Thrown at server-core/src/main/java/io/onedev/server/codequality/CoverageStats.java:96

			checkReportName(reportName);
		Long projectId = build.getProject().getId();
		Map<String, Map<Integer, CoverageStatus>> coveragesMap = OneDev.getInstance(ProjectService.class)
				.runOnActiveServer(projectId, new GetLineCoverages(projectId, build.getNumber(),
						blobPath, reportName));
		Map<Integer, CoverageStatus> coverages = new HashMap<>();
		for (var entry: coveragesMap.entrySet()) {
			if (SecurityUtils.canAccessReport(build, entry.getKey())) {
				entry.getValue().forEach((key, value) -> {
					coverages.merge(key, value, CoverageStatus::mergeWith);
				});
			}
		}
		return coverages;
	}

	private static void checkReportName(String reportName) {
		if (reportName.contains(".."))
			throw new ExplicitException("Invalid report name");
	}
	
	public void writeTo(File reportDir) {
		File reportFile = new File(reportDir, REPORT);
		try (var os = new BufferedOutputStream(new FileOutputStream(reportFile), BUFFER_SIZE)) {
			SerializationUtils.serialize(this, os);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public static String getReportLockName(Build build) {
		return getReportLockName(build.getProject().getId(), build.getNumber());
	}
	
	public static String getReportLockName(Long projectId, Long buildNumber) {
		return CoverageStats.class.getName() + ":"	+ projectId + ":" + buildNumber;
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Remove any ".." from the report name before calling the API
  2. Use a plain report name (single path segment, no traversal) and resolve parent directories outside the report name
  3. Sanitize/validate external input at the job or plugin boundary before passing it as a report name

Example fix

// before
var coverages = coverage.getLineCoverages("../other-project/report");
// after
String reportName = "unit-tests"; // no path separators or ".."
var coverages = coverage.getLineCoverages(reportName);
Defensive patterns

Strategy: validation

Validate before calling

// validate before calling CoverageStats APIs
if (reportName == null || reportName.contains(".."))
    throw new IllegalArgumentException("report name must not contain '..'");
if (reportName.contains("/") || reportName.contains("\\"))
    throw new IllegalArgumentException("report name must be a single path segment");

Type guard

function isValidReportName(name) { return typeof name === 'string' && name.length > 0 && !name.includes('..') && !/[/\\]/.test(name); }

Try / catch

try {
  coverages = CoverageStats.readFrom(reportDir, reportName);
} catch (ExplicitException e) {
  if ("Invalid report name".equals(e.getMessage())) {
    reportName = sanitizeReportName(reportName); // strip '..' and separators
    coverages = CoverageStats.readFrom(reportDir, reportName);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling CoverageStats.getLineCoverages(reportName) or readFrom(reportDir, reportName) with a reportName containing "..", e.g. "../secrets" or "a..b" patterns used as directory components.

Common situations: Untrusted report names piped from CI config, job step parameters, or REST payloads into the code quality report APIs; malicious or buggy build scripts passing relative paths as report names.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/8c6e455d5a10291c. Report an issue: GitHub.