{"record":{"id":"a41b13dc00a4c2b9","repo":"eclipse-vertx/vert.x","slug":"cannot-find-service-on-the-classpath-or-module-pat","errorCode":null,"errorMessage":"Cannot find service on the classpath or module path","messagePattern":"Cannot find service on the classpath or module path","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/impl/ServiceHelper.java","lineNumber":66,"sourceCode":"  public static <T> List<T> loadFactories(Class<T> clazz, ClassLoader classLoader) {\n    if (classLoader != null) {\n      return loadFactories(ServiceLoader.load(clazz, classLoader));\n    }\n    classLoader = Thread.currentThread().getContextClassLoader();\n    List<T> list = loadFactories(ServiceLoader.load(clazz, classLoader));\n    if (list.isEmpty() && classLoader != ServiceHelper.class.getClassLoader()) {\n      // By default, ServiceLoader.load uses the TCCL, this may not be enough in environment dealing with\n      // classloaders differently such as OSGi. So we should try to use the  classloader having loaded this\n      // class. In OSGi it would be the bundle exposing vert.x and so have access to all its classes.\n      list = loadFactories(ServiceLoader.load(clazz, ServiceHelper.class.getClassLoader()));\n    }\n    return list;\n  }\n\n  public static <T> T loadFactory(ServiceLoader<T> factories) {\n    T factory = loadFactoryOrNull(factories);\n    if (factory == null) {\n      throw new IllegalStateException(\"Cannot find service on the classpath or module path\");\n    }\n    return factory;\n  }\n\n  public static <T> T loadFactoryOrNull(ServiceLoader<T> factories) {\n    Collection<T> collection = loadFactories(factories);\n    if (!collection.isEmpty()) {\n      return collection.iterator().next();\n    } else {\n      return null;\n    }\n  }\n\n  public static <T> List<T> loadFactories(ServiceLoader<T> factories) {\n    List<T> list = new ArrayList<>();\n    if (factories.iterator().hasNext()) {\n      factories.iterator().forEachRemaining(list::add);\n      return list;","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/impl/ServiceHelper.java#L48-L84","documentation":"ServiceHelper.loadFactory(ServiceLoader) checks a supplied ServiceLoader for any provider instance and throws IllegalStateException('Cannot find service on the classpath or module path') when none is found. Same missing-SPI condition as the class-based variant, but resolution is done by the caller's ServiceLoader (supports module path).","triggerScenarios":"Creating a ServiceLoader.load(SomeSpi.class) that yields zero providers and passing it to loadFactory(loader) — no 'provides' in module-info and no META-INF/services entry.","commonSituations":"JPMS modularized apps missing `provides SomeSpi with SomeImpl`; classpath apps whose jar lacks the services descriptor; typos in the fully-qualified provider class name in META-INF/services/<interface>.","solutions":["Add a META-INF/services/<fully.qualified.Spi> file naming the implementation, or a `provides Spi with Impl;` clause in module-info.java","Verify the implementation jar is on the classpath/module path at runtime","Check the services file name exactly matches the SPI interface FQN (no whitespace/typos)","Use loadFactoryOrNull to handle absence gracefully"],"exampleFix":"// before\n// module-info.java has no provides clause\nrequires io.vertx.core;\n// after\nrequires io.vertx.core;\nprovides io.vertx.core.spi.cluster.ClusterManagerFactory\n    with io.vertx.spi.cluster.hazelcast.HazelcastClusterManagerFactory;","handlingStrategy":"fallback","validationCode":"boolean present = ServiceLoader.load(Spi.class).iterator().hasNext();\nif (!present) throw new IllegalStateException(\"No provider for \" + Spi.class.getName());","typeGuard":null,"tryCatchPattern":"try { impl = ServiceHelper.loadFactory(loader); } catch (IllegalStateException e) { impl = defaultImpl(); }","preventionTips":["Add `provides Spi with Impl;` in module-info for JPMS apps","Keep META-INF/services files with correct FQCN filenames","Verify with `jar --describe-module` or listing services entries in CI","Prefer passing your own instance over ServiceLoader in application code"],"tags":["service-loader","spi","classpath","jpms","missing-dependency"],"backgroundTag":"missing-optional-dependency","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}