flowable/flowable-engine · critical · FlowableException
Could not find an implementation of the org.flowable.cdi.spi
Error message
Could not find an implementation of the org.flowable.cdi.spi.ProcessEngineLookup service returning a non-null processEngine. Giving up.
What it means
During CDI container startup, FlowableExtension.lookupProcessEngine() iterates ProcessEngineLookup service implementations (via META-INF/services) to obtain a ProcessEngine. If no lookup is found — or all return null — it throws FlowableException, aborting initialization. The CDI module cannot function without a process engine.
Source
Thrown at modules/flowable-cdi/src/main/java/org/flowable/cdi/impl/FlowableExtension.java:105
return (-1) * ((Integer) o1.getPrecedence()).compareTo(o2.getPrecedence());
}
});
ProcessEngine processEngine = null;
for (ProcessEngineLookup processEngineLookup : discoveredLookups) {
processEngine = processEngineLookup.getProcessEngine();
if (processEngine != null) {
this.processEngineLookup = processEngineLookup;
LOGGER.debug("ProcessEngineLookup service {} returned process engine.", processEngineLookup.getClass());
break;
} else {
LOGGER.debug("ProcessEngineLookup service {} returned 'null' value.", processEngineLookup.getClass());
}
}
if (processEngineLookup == null) {
throw new FlowableException("Could not find an implementation of the org.flowable.cdi.spi.ProcessEngineLookup service " + "returning a non-null processEngine. Giving up.");
}
FlowableServices services = ProgrammaticBeanLookup.lookup(FlowableServices.class, beanManager);
services.setProcessEngine(processEngine);
return processEngine;
}
private void deployProcesses(ProcessEngine processEngine) {
new ProcessDeployer(processEngine).deployProcesses();
}
public void beforeShutdown(@Observes BeforeShutdown event) {
if (processEngineLookup != null) {
processEngineLookup.ungetProcessEngine();
processEngineLookup = null;
}
LOGGER.info("Shutting down flowable-cdi");View on GitHub (pinned to d6d39ce1c6)
Solutions
- Create META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup containing your implementation class (e.g. LocalProcessEngineLookup).
- Ensure the lookup's getProcessEngine() builds/returns a non-null engine (e.g. a StandaloneProcessEngineConfiguration with H2 datasource).
- Verify the implementation class is on the classpath and instantiable (public no-arg constructor).
Example fix
// before
(no services file) -> FlowableException at startup
// after
# file: META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup
org.myapp.MyProcessEngineLookup
public class MyProcessEngineLookup implements ProcessEngineLookup {
public ProcessEngine getProcessEngine() {
ProcessEngineConfiguration cfg = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration()
.setDatabaseSchemaUpdate("true");
return cfg.buildProcessEngine();
}
} Defensive patterns
Strategy: validation
Validate before calling
URL res = getClass().getResource("/META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup");
if (res == null) {
throw new IllegalStateException("Register a ProcessEngineLookup in META-INF/services");
} Try / catch
try {
// deploy/start the CDI app
} catch (FlowableException e) {
if (e.getMessage().contains("ProcessEngineLookup")) {
// add/fix the services registration before continuing
}
} Prevention
- Ship META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup with the app
- Ensure the lookup's getProcessEngine() never returns null
- Verify the services file class name matches an existing classpath class
- Re-check CDI wiring after flowable-cdi version migrations
When it happens
Trigger: Deploying an app using flowable-cdi without registering an org.flowable.cdi.spi.ProcessEngineLookup implementation in META-INF/services, or the registered lookup returns null from getProcessEngine().
Common situations: Missing META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup file after a migration to the new ServiceLoader mechanism; the old DefaultProcessEngineLookup/LocalProcessEngineLookup removed from auto-registration; typo in the services file class name.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- no org.flowable.app.engine.AppEngine defined in the applicat
- transactionManager is required property for SpringAppEngineC
- Failed to create property source
- Cannot use this method of the BusinessProcess bean within an
- Cannot use startProcessByName in an active command.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/7e2c110f78111e79.
Report an issue: GitHub.