junit-team/junit5 · error · PreconditionViolationException
temp directory must be a directory
Error message
temp directory must be a directory
What it means
Thrown as PreconditionViolationException inside the CloseablePath constructor when factory.createTempDirectory returned null or returned a Path that is not an existing directory (Files.isDirectory is false). The constructor closes the (already half-built) CloseablePath first to avoid leaking resources, then throws.
Solutions
- Fix the custom TempDirFactory so createTempDirectory always returns a directory that exists (use Files.createDirectories(...) before returning).
- Have the factory throw an exception rather than returning null when it cannot create the dir.
- Switch to the default factory if you do not need custom placement.
Example fix
// before
public Path createTempDirectory(AnnotatedElementContext ctx, ExtensionContext ec) {
return Path.of("/tmp/maybe-not-created"); // not actually a dir
}
// after
public Path createTempDirectory(AnnotatedElementContext ctx, ExtensionContext ec) throws IOException {
Path p = Path.of("/tmp/mybase").resolve("junit-" + UUID.randomUUID());
Files.createDirectories(p);
return p;
} Defensive patterns
Strategy: validation
Validate before calling
Path candidate = factory.createTempDirectory(ctx, ec);
if (candidate == null || !Files.isDirectory(candidate)) {
throw new IllegalStateException("Factory returned non-directory: " + candidate);
} Prevention
- Custom TempDirFactory.createTempDirectory must always create and return an existing directory (use Files.createDirectories).
- Have the factory throw rather than return null on failure.
- Add a unit test that asserts Files.isDirectory(out) after the factory call.
When it happens
Trigger: A custom TempDirFactory.createTempDirectory returns null or returns a path that does not exist / is a regular file. After this.dir is assigned, the precondition `this.dir == null || !Files.isDirectory(this.dir)` triggers close() then throws.
Common situations: Custom factory returns Paths.get("/some/path") without actually creating it; factory returns null on failure instead of throwing; factory returns a path that was concurrently deleted; misbehaving factory in a library.
Related errors
- Failed to create default temp directory
- temp directory with non-default file system cannot be…
- Can only resolve @TempDir
- @TempDir field [ ] must not be declared as final.
- Unsupported AnnotatedElement type for @TempDir
AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11).
Data as JSON: /api/errors/5845f25dbb060efd.
Report an issue: GitHub.
Appendix: source
Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java:273
static class CloseablePath implements Store.CloseableResource, AutoCloseable {
private final @Nullable Path dir;
private final TempDirFactory factory;
private final Cleanup cleanup;
private final AnnotatedElementContext elementContext;
private final ExtensionContext extensionContext;
private CloseablePath(TempDirFactory factory, Cleanup cleanup, Class<?> elementType,
AnnotatedElementContext elementContext, ExtensionContext extensionContext) throws Exception {
this.dir = factory.createTempDirectory(elementContext, extensionContext);
this.factory = factory;
this.cleanup = cleanup;
this.elementContext = elementContext;
this.extensionContext = extensionContext;
if (this.dir == null || !Files.isDirectory(this.dir)) {
close();
throw new PreconditionViolationException("temp directory must be a directory");
}
if (elementType == File.class && !this.dir.getFileSystem().equals(FileSystems.getDefault())) {
close();
throw new PreconditionViolationException(
"temp directory with non-default file system cannot be injected into " + File.class.getName()
+ " target");
}
}
Path get() {
return requireNonNull(this.dir);
}
@Override
public void close() throws IOException {
try {
if (this.dir != null) {View on GitHub (pinned to f070c699a0)