provectus/kafka-ui · error · IllegalStateException

No archive files were found

Error message

No archive files were found

What it means

CustomSerdeLoader.createClassloader scans the configured serde location for archive files (jar/zip). If the path exists but contains no archives, it throws IllegalStateException('No archive files were found') because an empty directory cannot yield any serde classes to load.

Solutions

  1. Place the serde jar (or zip) into the configured directory
  2. Point filePath directly at the jar file or a directory that contains it
  3. Check archive extension is one the loader recognizes (jar/zip)
  4. Re-run the build/copy step that was supposed to populate the directory

Example fix

// before
filePath: /opt/serdes/   # empty directory
// after
filePath: /opt/serdes/my-serde-1.0.jar
Defensive patterns

Strategy: validation

Validate before calling

Path loc = Path.of(cfg.getFilePath());
try (var s = Files.list(loc)) {
  if (s.noneMatch(p -> p.toString().endsWith(".jar") || p.toString().endsWith(".zip")))
    throw new IllegalStateException("No archives in " + loc);
}

Try / catch

try {
  classloader = CustomSerdeLoader.serdeClassloader(location);
} catch (IllegalStateException e) {
  log.error("No serde archives at {}: {}", location, e.getMessage());
  throw e;
}

Prevention

When it happens

Trigger: filePath points to an existing but empty directory, or a directory containing only non-archive files (txt, class files unpacked, .so, etc.).

Common situations: Volume mounted but jar not copied in; user points filePath at a directory of extracted class files instead of the jar; archive has an unsupported extension; download/CI step failed silently leaving an empty dir.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of provectus/kafka-ui@83b5a60cc0 (2026-09-08). Data as JSON: /api/errors/7f19e711692cb993. Report an issue: GitHub.

Appendix: source

Thrown at kafka-ui-api/src/main/java/com/provectus/kafka/ui/serdes/CustomSerdeLoader.java:86

      List<URL> archiveFiles = new ArrayList<>();
      try (var files = Files.walk(location)) {
        var paths = files.filter(CustomSerdeLoader::isArchive).collect(Collectors.toList());
        for (Path path : paths) {
          archiveFiles.add(path.toUri().toURL());
        }
      }
      return archiveFiles;
    }
    return List.of();
  }

  private ClassLoader createClassloader(Path location) {
    if (!Files.exists(location)) {
      throw new IllegalStateException("Location does not exist");
    }
    var archives = findArchiveFiles(location);
    if (archives.isEmpty()) {
      throw new IllegalStateException("No archive files were found");
    }
    // we assume that location's content does not change during serdes creation
    // so, we can reuse already created classloaders
    return classloaders.computeIfAbsent(location, l ->
        AccessController.doPrivileged(
            (PrivilegedAction<URLClassLoader>) () ->
                new ChildFirstClassloader(
                    archives.toArray(URL[]::new),
                    CustomSerdeLoader.class.getClassLoader())));
  }

  //---------------------------------------------------------------------------------

  // This Classloader first tries to load classes by itself. If class not fount
  // search is propagated to parent (this is opposite to how usual classloaders work)
  private static class ChildFirstClassloader extends URLClassLoader {

    private static final String JAVA_PACKAGE_PREFIX = "java.";

View on GitHub (pinned to 83b5a60cc0)