eclipse-vertx/vert.x · error · VertxException

Nesting more than two levels is not supported

Error message

Nesting more than two levels is not supported

What it means

FileResolverImpl.unpackFromJarURL throws this VertxException when it encounters a jar-within-jar (or deeper) URL scheme while extracting a resource from an embedded jar. Vert.x's file resolver only understands at most two levels of nesting (e.g. an entry inside a jar), and any deeper 'jar:file:...!/...!/...' URL falls into the default switch branch. It is an internal invariant check protecting the unpacking algorithm, not a user-recoverable condition.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/file/impl/FileResolverImpl.java:364

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                  Path relative = path.relativize(file);
                  cache.cacheFile(relative.toString(), file.toFile(), false);
                  return FileVisitResult.CONTINUE;
                }
              });
            } else {
              // jar:file:/path/to/nesting.jar!/path/to/nested.jar
              try (ZipFile zip = new ZipFile(root)) {
                extractFilesFromJarFile(zip, fileName);
              }
            }
          } else {
            throw new VertxException("Unexpected nested url : " + nestedURL);
          }
          break;
        default:
          throw new VertxException("Nesting more than two levels is not supported");
      }
    } catch (IOException e) {
      throw new VertxException(FileSystemImpl.getFileAccessErrorMessage("unpack", url.toString()), e);
    }
    return cache.getFile(fileName);
  }

  /**
   * Extract a subset of the entries to the cache.
   */
  private void extractFilesFromJarFile(ZipFile zip, String entryFilter) throws IOException {
    Enumeration<? extends ZipEntry> entries = zip.entries();
    while (entries.hasMoreElements()) {
      ZipEntry entry = entries.nextElement();
      String name = entry.getName();
      int len = name.length();
      if (len == 0) {
        return;

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Run the application as a single-level fat jar (use the standard vertx-maven-plugin / gradle shadowJar packaging) so resources sit directly in the top jar.
  2. If using Spring Boot nested jars, launch via Spring Boot's launcher/classloader rather than Vert.x's FileResolver, or extract the jar before running (java -Dvertx.disableFileCPResolving=true after unpacking).
  3. Set vertx.disableFileCPResolving=true and copy the resource out yourself with java.util.zip APIs that support arbitrary nesting.
  4. Restructure the artifact so the resource is a direct classpath entry (move it out of the nested jar).

Example fix

// before: resources inside a Spring Boot nested jar read via vertx.fileSystem().readFile("config.json")
// after: launch with Boot loader or extract first
java -jar app.jar  // Boot LaunchedURLClassLoader handles nesting
// or in Docker:
RUN java -Djarmode=tools -jar app.jar extract --destination /app
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Defensive patterns

Strategy: validation

Validate before calling

URL url = cl.getResource(name);
int depth = 0;
for (int i = 0; i < url.toString().length() - 1; i++)
  if (url.toString().charAt(i) == '!' && url.toString().charAt(i + 1) == '/') depth++;
if (depth > 1) throw new IllegalStateException(
    "Resource nested more than two levels deep: " + url +
    " — flatten the jar layout or disable FileCP resolving");

Type guard

static boolean isOverlyNestedJarUrl(URL url) {
  String s = url.toString();
  return s.startsWith("jar:") && s.split("!").length > 2;
}

Try / catch

try {
  vertx.fileSystem().readFileBlocking(resource);
} catch (VertxException e) {
  if (e.getMessage().contains("Nesting more than two levels")) {
    // fall back to ClassLoader stream read
  } else throw e;
}

Prevention

When it happens

Trigger: Calling vertx.fileSystem().propsAsync/copy etc. (or deploying verticles) where a resource on the classpath resolves to a URL with more than two '!' nesting levels, typically 'jar:jar:file:...!/inner.jar!/resource' produced by fat jars nested inside fat jars or Spring Boot nested-jar layout used without its own classloader.

Common situations: Spring Boot executable jars (Boot's nested jar: URLs) run through plain Vert.x classloading; shading an uber-jar that itself gets repackaged; running from a jar extracted into another jar by a build plugin; container images that bundle the app jar inside a second jar.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/c7fe47ea301e2fd8. Report an issue: GitHub.