quarkusio/quarkus · error · RuntimeException

Unable to read

Error message

Unable to read 

What it means

Thrown by PathTreeClassPathElement.getData() when the bytes of a classpath resource cannot be read from its containing JAR. The library wraps the underlying IOException (e.g. ZipException) in a RuntimeException, either after attempting to re-open a jar whose file handle went stale, or directly when reading fails.

Source

Thrown at independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/PathTreeClassPathElement.java:325

                                lock.readLock().lock();
                            }
                        }
                    } catch (IOException e) {
                        if (pathTree.isOpen()) {
                            //this is a weird corner case, that should not really affect end users, but is super annoying
                            //if you are actually working on Quarkus. If you rebuild quarkus while you have an application
                            //running reading from the rebuilt zip file will fail, but some of these classes are needed
                            //for a clean shutdown, so the Java process hangs and needs to be forcibly killed
                            //this effectively attempts to reopen the file, allowing shutdown to work.
                            //we need to do this here as close needs a write lock while withJarFile takes a readLock
                            log.error("Failed to read " + name
                                    + " attempting to re-open the zip file. It is likely a jar file changed on disk, you should shutdown your application",
                                    e);
                            lock.readLock().unlock();
                            try {
                                close();
                            } catch (IOException ignore) {
                                throw new RuntimeException("Unable to read " + name, e.getCause());
                            } finally {
                                lock.readLock().lock();
                            }
                        } else {
                            throw new RuntimeException("Unable to read " + name, e);
                        }
                    }
                }
                // reading the entry directly from the JAR
                final boolean interrupted = Thread.interrupted();
                try {
                    return pathTree.getOriginalTree().apply(name, visit -> {
                        if (visit == null) {
                            return null;
                        }
                        try {
                            return Files.readAllBytes(visit.getPath());
                        } catch (IOException e) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Stop the running application, rebuild, and start it again so the classloader picks up the fresh jar
  2. Identify which process or build step is rewriting the jar while the app runs and serialize them (e.g. don't run 'mvn install' on a jar used by a live dev-mode app)
  3. If the error persists on a stable jar, verify the jar's integrity (jar tf / unzip -t) and rebuild it
  4. Restart dev-mode if an external build (e.g. IDE) touched target/ jars mid-run

Example fix

// before (external process overwrote jar while app runs)
mvn install &
./mvnw quarkus:dev  # reads jar concurrently -> Unable to read
// after
./mvnw install
./mvnw quarkus:dev  # build finishes before dev mode starts
Defensive patterns

Strategy: retry

Validate before calling

Path jar = Paths.get(jarPath);
if (!Files.isRegularFile(jar) || !Files.isReadable(jar)) {
    throw new IllegalStateException("Jar missing/unreadable: " + jar);
}
try (var zf = new java.util.zip.ZipFile(jar.toFile())) {
    if (zf.getEntry(resourceName) == null) throw new IllegalStateException("Entry missing: " + resourceName);
}

Try / catch

try {
    byte[] data = element.getData(resourceName);
} catch (RuntimeException e) {
    // message starts with "Unable to read " — jar likely changed on disk
    // restart the application / recreate the classloader, do not retry in-place
}

Prevention

When it happens

Trigger: Calling getData() on a classpath element backed by a jar file that was modified, replaced, or deleted on disk while the classloader held it open (the code detects a changed jar, tries close() + re-open, and gives up if that still fails), or an IOException reading the zip entry.

Common situations: Rebuilding/redeploying a jar while a dev-mode or test application is still running; Maven/Gradle overwriting the jar during a build; file-sync in a container or NFS causing the jar inode to change; corrupted or partially-written jar files.

Related errors


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