YunaiV/yudao-cloud · critical · FlowableException

couldn't lookup datasource from {}: {}

Error message

couldn't lookup datasource from {}: {}

What it means

Flowable's AbstractEngineConfiguration.initDataSource() tries InitialContext().lookup(dataSourceJndiName) when no DataSource bean was injected. Any NamingException/ClassCastException/communication failure from the JNDI provider is wrapped in this FlowableException, including the JNDI name in the message.

Source

Thrown at sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java:446

    /**
     * Define a max length for storing String variable types in the database. Mainly used for the Oracle NVARCHAR2 limit of 2000 characters
     */
    protected int maxLengthStringVariableType = -1;

    protected void initEngineConfigurations() {
        addEngineConfiguration(getEngineCfgKey(), getEngineScopeType(), this);
    }

    // DataSource
    // ///////////////////////////////////////////////////////////////

    protected void initDataSource() {
        if (dataSource == null) {
            if (dataSourceJndiName != null) {
                try {
                    dataSource = (DataSource) new InitialContext().lookup(dataSourceJndiName);
                } catch (Exception e) {
                    throw new FlowableException("couldn't lookup datasource from " + dataSourceJndiName + ": " + e.getMessage(), e);
                }

            } else if (jdbcUrl != null) {
                if ((jdbcDriver == null) || (jdbcUsername == null)) {
                    throw new FlowableException("DataSource or JDBC properties have to be specified in a process engine configuration");
                }

                logger.debug("initializing datasource to db: {}", jdbcUrl);

                if (logger.isInfoEnabled()) {
                    logger.info("Configuring Datasource with following properties (omitted password for security)");
                    logger.info("datasource driver : {}", jdbcDriver);
                    logger.info("datasource url : {}", jdbcUrl);
                    logger.info("datasource user name : {}", jdbcUsername);
                }

                PooledDataSource pooledDataSource = new PooledDataSource(this.getClass().getClassLoader(), jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword);

View on GitHub (pinned to 477be9dd49)

Solutions

  1. Verify the exact JNDI name against the server's JNDI tree (e.g. WildFly admin console, Tomcat's ResourceLink + web.xml resource-ref).
  2. On Spring Boot / standalone, skip JNDI and configure jdbcUrl/jdbcDriver/jdbcUsername directly, or inject a DataSource bean via setDataSource().
  3. Ensure the lookup target is really a javax.sql.DataSource and the app has permission to read it.
  4. For embedded Tomcat, register the resource in server.context.xml (or TomcatServletWebServerFactory customization) and the ResourceLink in context.xml.

Example fix

// before
cfg.setDataSourceJndiName("java:comp/env/jdbc/flowable"); // fails in Spring Boot

// after
cfg.setJdbcUrl("jdbc:dm://localhost:5236");
cfg.setJdbcDriver("dm.jdbc.driver.DmDriver");
cfg.setJdbcUsername("SYSDBA");
cfg.setJdbcPassword("***");
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast before engine build with a clear message
if (cfg.getDataSource() == null && cfg.getDataSourceJndiName() != null) {
    try {
        DataSource ds = (DataSource) new InitialContext().lookup(cfg.getDataSourceJndiName());
        Assert.notNull(ds, "JNDI name resolved to null");
    } catch (Exception e) {
        throw new IllegalStateException("JNDI datasource unavailable: " + cfg.getDataSourceJndiName(), e);
    }
}

Try / catch

try {
    processEngine = cfg.buildProcessEngine();
} catch (FlowableException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("couldn't lookup datasource")) {
        // fall back to direct JDBC config or fail with actionable guidance
        throw new IllegalStateException("Configure a valid JNDI name or set jdbc* properties", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: ProcessEngineConfiguration is built with setDataSourceJndiName("java:comp/env/jdbc/ds") but the app runs outside a container with no JNDI tree, or the name is misspelled, or the bound object is not a javax.sql.DataSource (cast fails), or the app server resource is not deployed/started.

Common situations: Moving a Flowable app from a full app server (WildFly/TomEE with JNDI) to Spring Boot embedded Tomcat which has no java:comp/env by default; typos in the JNDI name; resource adapter not yet published during early startup; running unit tests without a JNDI implementation.

Related errors


AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14). Data as JSON: /api/errors/57310b6c6875c3f2. Report an issue: GitHub.