quarkusio/quarkus · critical

Internal error: An attempt was made to start an application

Error message

Internal error: An attempt was made to start an application which had already been started and closed. The affected ClassLoader is ${runtimeClassLoader}

What it means

StartupActionImpl.run() starts the application using its runtime class loader. If that class loader has already been closed (application previously started and shut down), starting it again is impossible and the framework throws this internal-error RuntimeException naming the affected class loader.

Source

Thrown at core/deployment/src/main/java/io/quarkus/runner/bootstrap/StartupActionImpl.java:378

        try {
            Class<?> overrideConfigSourceClass = runtimeClassLoader
                    .loadClass("io.quarkus.devservice.runtime.config.DevServicesOverrideConfigSource");
            overrideConfigSourceClass.getMethod("setConfig", Map.class).invoke(null, startResult.overrideConfigs());
        } catch (ClassNotFoundException e) {
            // devservices runtime module not available
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException("Failed to set dev services override config", e);
        }
    }

    /**
     * Runs the application, and returns a handle that can be used to shut it down.
     */
    public RunningQuarkusApplication run(String... args) throws Exception {

        if (runtimeClassLoader.isClosed()) {
            throw new RuntimeException(
                    "Internal error: An attempt was made to start an application which had already been started and closed. The affected ClassLoader is "
                            + runtimeClassLoader);

        }
        // Start dev services that weren't started in the augmentation phase
        ensureDevServicesStarted();
        InitialConfigurator.DELAYED_HANDLER.buildTimeComplete();

        //first we hack around class loading in the fork join pool
        ForkJoinClassLoading.setForkJoinClassLoader(runtimeClassLoader);

        //we have our class loaders
        ClassLoader old = Thread.currentThread().getContextClassLoader();
        try {
            Thread.currentThread().setContextClassLoader(runtimeClassLoader);
            // force init here
            Class<?> appClass = Class.forName(applicationClassName, true, runtimeClassLoader);
            Method start = appClass.getMethod("start", String[].class);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Create a fresh StartupAction via createInitialRuntimeApplication() and run() that instead of reusing the old one
  2. Track application lifecycle: never call run() after the RunningQuarkusApplication was closed
  3. In tests, use the framework's per-test-class lifecycle rather than manual run() calls
  4. If this appears unexpectedly, check for double-invocation of run() in your bootstrap code

Example fix

// before
startupAction.run();
...
runningApp.close();
startupAction.run(); // throws: closed classloader
// after
startupAction.run();
...
runningApp.close();
StartupActionImpl fresh = augmentAction.createInitialRuntimeApplication();
fresh.run();
Defensive patterns

Strategy: validation

Validate before calling

// before run()
if (startupAction.isClosed()) { startupAction = augmentAction.createInitialRuntimeApplication(); }
startupAction.run();

Try / catch

try { action.run(); } catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().contains("already been started and closed")) { /* create a fresh StartupAction */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling run() (directly or via test hooks like beforeAll) on a StartupActionImpl whose runtime class loader was closed by a previous run/stop cycle — e.g. running an application twice, or a test lifecycle reusing a closed StartupAction.

Common situations: Re-running a completed QuarkusTest lifecycle; custom harnesses calling run() after stop()/close(); reusing a StartupAction across test classes.

Related errors


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