junit-team/junit5 · error · JUnitException

Expected file name with file extension, but got

Error message

Expected file name with file extension, but got: ${fileName}

What it means

JUnitException thrown by SearchPathUtils.removeExtension when a file name contains no '.' (no extension). removeExtension is called from determineSimpleClassName and isModuleInfoOrPackageInfo during module classpath scanning. The upstream filter only passes .class/.java files (which always have extensions), so reaching this guard means an extension-less name slipped through filtering - a defensive failure.

Solutions

  1. Ensure the path is a .class/.java file before invoking SearchPathUtils.determineSimpleClassName
  2. If reached through standard scanning, report a bug to JUnit with the offending classpath/module entry
  3. Remove non-class files from module or jar entries that should not be scanned
Defensive patterns

Strategy: validation

Validate before calling

if (fileName.indexOf('.') < 0) {
    // skip - not a class/source file; do not call removeExtension
}

Prevention

When it happens

Trigger: A path whose final segment has no '.' reaches SearchPathUtils.removeExtension - e.g. via custom calling code invoking SearchPathUtils internals directly, or an upstream filter bug that lets an extension-less file through to class-name derivation.

Common situations: Rare; would indicate either a custom caller of SearchPathUtils internals on an arbitrary path, a malformed module entry, or a bug in upstream filtering. Standard scanning pre-filters to .class/.java which always have extensions.

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/636b4283ab137d85. Report an issue: GitHub.

Appendix: source

Thrown at junit-platform-commons/src/main/java/org/junit/platform/commons/util/SearchPathUtils.java:72

		var simpleClassName = determineSimpleClassName(path);
		var parent = path.getParent();
		return parent == null ? simpleClassName : joinPathNamesWithPackageSeparator(parent.resolve(simpleClassName));
	}

	private static String joinPathNamesWithPackageSeparator(Path path) {
		return IntStream.range(0, path.getNameCount()) //
				.mapToObj(i -> path.getName(i).toString()) //
				.collect(joining(PACKAGE_SEPARATOR_STRING));
	}

	static String determineSimpleClassName(Path file) {
		return removeExtension(file.getFileName().toString());
	}

	private static String removeExtension(String fileName) {
		int lastDot = fileName.lastIndexOf(FILE_NAME_EXTENSION_SEPARATOR_CHAR);
		if (lastDot < 0) {
			throw new JUnitException("Expected file name with file extension, but got: " + fileName);
		}
		return fileName.substring(0, lastDot);
	}

	private static boolean isClassOrSourceFile(String name) {
		return name.endsWith(CLASS_FILE_SUFFIX) || (SOURCE_MODE && name.endsWith(SOURCE_FILE_SUFFIX));
	}

	private static boolean isClassFile(Path file) {
		return file.getFileName().toString().endsWith(CLASS_FILE_SUFFIX);
	}

	private SearchPathUtils() {
	}
}

View on GitHub (pinned to f070c699a0)