quarkusio/quarkus · error · IllegalStateException

Cannot create a RunningDevServicesDatasource before the H2 d

Error message

Cannot create a RunningDevServicesDatasource before the H2 datasource has been started.

What it means

H2 Dev Services creates a RunningDevServicesDatasource lazily via an anonymous DevServicesDatasourceProvider. This error means the provider's runningDevServicesDatasource() accessor was called before start() had produced an H2 file JDBC connection URL, so connectionUrl is still null. Unlike container-based providers, H2 runs in-process, so there is no container ID to query — the URL is the only start indicator.

Source

Thrown at extensions/devservices/h2/src/main/java/io/quarkus/devservices/h2/deployment/H2DevServicesProcessor.java:139

                                                + tcpServer.getStatus());
                            }
                        }

                        @Override
                        public String getConnectionInfo() {
                            return getEffectiveJdbcUrl();
                        }

                        @Override
                        public String getContainerId() {
                            return null;
                        }

                        @Override
                        public DevServicesDatasourceProvider.RunningDevServicesDatasource runningDevServicesDatasource() {
                            // Override, so we can check the connection url instead of the container id
                            if (connectionUrl == null) {
                                throw new IllegalStateException(
                                        "Cannot create a RunningDevServicesDatasource before the H2 datasource has been started.");
                            }
                            // It would be nice to cache this, but since this is an interface, it can't be done at this level, and would have to be done by every implementing class
                            return new DevServicesDatasourceProvider.RunningDevServicesDatasource(getContainerId(),
                                    getEffectiveJdbcUrl(),
                                    getReactiveUrl(), getUsername(), getPassword());
                        }

                    };
                } catch (SQLException throwables) {
                    throw new RuntimeException(throwables);
                }
            }

            @Override
            public Optional<DevServicesDatasourceProvider.RunningDevServicesDatasource> findRunningComposeDatasource(
                    LaunchMode launchMode, boolean useSharedNetwork, DevServicesDatasourceContainerConfig containerConfig,
                    DevServicesComposeProjectBuildItem composeProjectBuildItem) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure start() on the H2 provider is invoked (via DevServicesProcessor build steps) before calling runningDevServicesDatasource()
  2. Check that quarkus.datasource.devservices.enabled is not set to false while code still expects a started datasource
  3. Consume the DevServicesResultBuildItem produced by DevServicesProcessor instead of poking the provider directly
  4. If the datasource should never be started by dev services, avoid the provider entirely and build the JDBC URL from quarkus.datasource.jdbc.url

Example fix

// before
var running = h2Provider.runningDevServicesDatasource(); // throws before start
// after
var result = h2Provider.start(launchConfig, devServicesConfig); // sets connectionUrl
var running = h2Provider.runningDevServicesDatasource();
Defensive patterns

Strategy: validation

Validate before calling

if (provider instanceof H2DevServicesProviderCapture) {
    // only call after DevServicesProcessor produced the datasource start result
    var result = devServicesResultBuildItem; // from DevServicesProcessor build step
    if (result == null || result.getConnectionInfo() == null) {
        throw new IllegalStateException("H2 dev services not started yet");
    }
}
var running = provider.runningDevServicesDatasource();

Type guard

boolean isH2DevServicesStarted(DevServicesDatasourceProvider p) {
    try { p.runningDevServicesDatasource(); return true; }
    catch (IllegalStateException e) { return false; }
}

Try / catch

try {
    var running = provider.runningDevServicesDatasource();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("before the H2 datasource has been started")) {
        // fall back: compute URL from config or defer until after start()
    } else throw e;
}

Prevention

When it happens

Trigger: Calling runningDevServicesDatasource() on the H2 DevServicesDatasourceProvider before the start() method has completed and set connectionUrl; or when start() did not run / returned no URL (e.g. dev services disabled, inline datasource already configured).

Common situations: Custom build steps or dev-mode tooling consuming the DevServicesDatasourceProvider during augmentation before DevServicesProcessor start phases ran; tests or recorders probing the datasource URL too early; disabling quarkus.datasource.devservices.enabled but still querying the provider.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/98f3fdd0c81a701e. Report an issue: GitHub.