quarkusio/quarkus · error · IllegalArgumentException

File is not a regular file: ${file}

Error message

File is not a regular file: ${file}

What it means

PathPart wraps a regular file for range-based response streaming. It throws this IllegalArgumentException when the Path exists but is not a regular file (e.g. a directory or special file), because only regular files support byte-range reads of a known size.

Source

Thrown at independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/PathPart.java:39

    public final long offset;

    /**
     * The number of bytes to send
     */
    public final long count;

    /**
     * Create a new partial {@link Path} object.
     *
     * @param file The file to send
     * @param offset The starting byte of the file (must be >= 0)
     * @param count The number of bytes to send (must be >= 0 and offset+count <= file size)
     */
    public PathPart(Path file, long offset, long count) {
        if (!Files.exists(file))
            throw new IllegalArgumentException("File does not exist: " + file);
        if (!Files.isRegularFile(file))
            throw new IllegalArgumentException("File is not a regular file: " + file);
        if (!Files.isReadable(file))
            throw new IllegalArgumentException("File cannot be read: " + file);
        if (offset < 0)
            throw new IllegalArgumentException("Offset (" + offset + ") must be >= 0: " + file);
        if (count < 0)
            throw new IllegalArgumentException("Count (" + count + ") must be >= 0: " + file);
        long fileLength;
        try {
            fileLength = Files.size(file);
            if ((offset + count) > fileLength)
                throw new IllegalArgumentException(
                        "Offset + count (" + (offset + count) + ") larger than file size (" + fileLength + "): " + file);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
        this.file = file;
        this.offset = offset;
        this.count = count;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Check `Files.isDirectory(file)` in the caller and return 404 or redirect instead of constructing PathPart.
  2. Point PathPart at the concrete file, not a directory; append the filename when the user requests a folder path.
  3. Normalize/validate user-supplied paths (reject directory or symlink targets) before constructing the part.

Example fix

// before
Path requested = Path.of(baseDir, userPath);
PathPart part = new PathPart(requested, 0, Files.size(requested));
// after
Path requested = Path.of(baseDir, userPath).normalize();
if (!requested.startsWith(baseDir) || !Files.isRegularFile(requested)) {
    return Response.status(Response.Status.NOT_FOUND).build();
}
PathPart part = new PathPart(requested, 0, Files.size(requested));
Defensive patterns

Strategy: validation

Validate before calling

if (file == null || !Files.isRegularFile(file)) {
    return Response.status(Response.Status.NOT_FOUND).build();
}

Type guard

boolean isRegularFile(Path p) {
    return p != null && Files.isRegularFile(p);
}

Try / catch

try {
    return Response.ok(new PathPart(file, offset, count)).build();
} catch (IllegalArgumentException e) {
    return Response.status(Response.Status.NOT_FOUND).build();
}

Prevention

When it happens

Trigger: Calling `new PathPart(file, offset, count)` with a Path that points to a directory, a device/special file, or (on some platforms) a named pipe — `Files.isRegularFile(file)` returns false.

Common situations: Serving a directory listing path passed directly to the file API; path-traversal requests that resolve to a directory or /dev/ entry; symlink targets pointing at sockets/pipes; OpenAPI/docs examples that treat an upload directory as a downloadable file.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/2b60cfc8aed3eac7. Report an issue: GitHub.