elastic/elasticsearch · error · InvalidUserDataException

Missing 'classesDirs' or 'classpath' property.

Error message

Missing 'classesDirs' or 'classpath' property.

What it means

Thrown by CacheCacheableTestFixtures.createClassLoader(FileCollection) when the classpath argument is null. The task needs a classpath to build a URLClassLoader for loading/processing test fixtures; a null classpath means the task was wired without its required 'classpath' (or 'classesDirs') property. It is a configuration-time guard, not a runtime IO failure.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/packer/CacheCacheableTestFixtures.java:114

                            e.printStackTrace();
                        }
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                // Close the classloader to free resources:
                try {
                    if (urlLoader != null) urlLoader.close();
                } catch (IOException ioe) {
                    // getLogger().warn("Cannot close classloader: ".concat(ioe.toString()));
                }
            }
        }

        private URLClassLoader createClassLoader(FileCollection classpath) {
            if (classpath == null) {
                throw new InvalidUserDataException("Missing 'classesDirs' or 'classpath' property.");
            }

            final Set<File> cpElements = new LinkedHashSet<>();
            cpElements.addAll(classpath.getFiles());
            final URL[] urls = new URL[cpElements.size()];
            try {
                int i = 0;
                for (final File cpElement : cpElements) {
                    urls[i++] = cpElement.toURI().toURL();
                }
                assert i == urls.length;
            } catch (MalformedURLException mfue) {
                throw new InvalidUserDataException("Failed to build classpath URLs.", mfue);
            }

            return URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader());
        }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Find the task registration (search for the task type / the register call) and confirm classpath and classesDirs are assigned.
  2. Set classpath from the relevant source set: fixturesTask.classpath = sourceSets.fixtures.runtimeClasspath.
  3. If the task genuinely needs no classpath, switch to an overload that does not create a classloader, or guard createClassLoader against null callers.
  4. After fixing, run the specific task with --rerun-tasks to confirm.

Example fix

// before
// task not given a classpath

// after
tasks.named('cacheCacheableTestFixtures', CacheCacheableTestFixtures) {
  classpath = sourceSets.test.runtimeClasspath
}
Defensive patterns

Strategy: validation

Validate before calling

// In the task registration, assert the property is wired before execution
tasks.named('cacheCacheableTestFixtures').configure(t -> {
    if (((CacheCacheableTestFixtures) t).getClasspath() == null) {
        throw new InvalidUserDataException("cacheCacheableTestFixtures requires 'classpath' to be set");
    }
});

Prevention

When it happens

Trigger: A build script or plugin registers a CacheCacheableTestFixtures (or equivalent) task but never calls .classpath(...) / .classesDirs(...), so the property stays null when createClassLoader runs at execution time.

Common situations: Copying a task registration from another project and forgetting to wire the classpath; renaming a property during a refactor without updating the registration; a custom subproject that opts into cacheable test fixtures but has no test source set to derive the classpath from.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/194cb55b279c5aa7. Report an issue: GitHub.