{"record":{"id":"913e3a907f279fc9","repo":"quarkusio/quarkus","slug":"classloader-is-not-resettable","errorCode":null,"errorMessage":"Classloader is not resettable","messagePattern":"Classloader is not resettable","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java","lineNumber":233,"sourceCode":"        if (name.startsWith(\"/\")) {\n            name = name.substring(1);\n        }\n        if (name.endsWith(\"/\")) {\n            name = name.substring(0, name.length() - 1);\n        }\n        return name;\n    }\n\n    private boolean parentFirst(String name, ClassPathResourceIndex classPathResourceIndex) {\n        return parentFirst || name.startsWith(\"io/quarkus/devservices/crossclassloader\")\n                || classPathResourceIndex.isParentFirst(name);\n    }\n\n    public void reset(Map<String, byte[]> generatedResources, Map<String, byte[]> transformedClasses) {\n        ensureOpen();\n\n        if (resettableElement == null) {\n            throw new IllegalStateException(\"Classloader is not resettable\");\n        }\n        synchronized (this) {\n            // we don't want the previous MemoryClassPathElement to leak as a key of protectionDomains\n            protectionDomains.remove(this.transformedClasses);\n            this.transformedClasses = new MemoryClassPathElement(transformedClasses, true);\n            resettableElement.reset(generatedResources);\n            classPathResourceIndex = null;\n        }\n    }\n\n    /**\n     * Returns all in-memory generated and transformed class bytes, keyed by\n     * resource path (e.g. {@code io/quarkus/runner/Foo.class}).\n     * <p>\n     * Classes are collected in classloader priority order: transformed classes\n     * first, then resettable element, then normal priority elements, then\n     * lesser priority elements. Only {@link MemoryClassPathElement} instances\n     * are included. Uses {@code putIfAbsent} so higher-priority entries win.","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/classloading/QuarkusClassLoader.java#L215-L251","documentation":"QuarkusClassLoader.reset() can only be called on a classloader that was created with a resettable element (a memory class-path element that supports regeneration). If the loader has no resettableElement, reset() throws IllegalStateException(\"Classloader is not resettable\").","triggerScenarios":"Calling QuarkusClassLoader.reset(generatedResources, transformedClasses) on a loader built without the resettable flag — e.g. a base/production QuarkusClassLoader rather than the dev-mode or test resettable loader.","commonSituations":"Invoking reset() from custom tooling on a non-resettable classloader; live-reload code paths executed against a loader created without reset support; mixing up the base loader with the application loader in tests.","solutions":["Only call reset() on the QuarkusClassLoader instance created for dev mode / the StartupAction, not the base loader","Check how the classloader was constructed and enable the resettable memory element if you control creation","Replace the classloader (restart the StartupAction) instead of resetting when the loader is not resettable"],"exampleFix":"// before\nbaseQuarkusClassLoader.reset(newResources, transformed); // IllegalStateException\n// after\nQuarkusClassLoader appLoader = (QuarkusClassLoader) startupAction.getClassLoader();\nappLoader.reset(newResources, transformed);","handlingStrategy":"type-guard","validationCode":"public static void resetIfResettable(QuarkusClassLoader cl, Map<String, byte[]> gen, Map<String, byte[]> transformed) {\n    if (cl == null) throw new IllegalStateException(\"No application classloader\");\n    cl.reset(gen, transformed);\n}","typeGuard":"boolean isResettable(QuarkusClassLoader cl) {\n    // only dev-mode / startup-action loaders are resettable\n    return cl != null && cl.getParent() != null\n        && \"io.quarkus.dev.runtime.QuarkusClassLoader\".equals(cl.getClass().getName()) == false\n        ? cl.getClass().getName().contains(\"QuarkusClassLoader\") : cl != null;\n}\n// safer: track the loader you got from the StartupAction and only reset that instance","tryCatchPattern":"try {\n    loader.reset(generated, transformed);\n} catch (IllegalStateException e) {\n    // loader not resettable -> restart the StartupAction instead of resetting\n}","preventionTips":["Only reset the classloader obtained from the current StartupAction / dev-mode context","Never call reset() on the base (root) QuarkusClassLoader","If unsure, create a new StartupAction rather than resetting"],"tags":["classloading","devmode","illegalstate","hot-reload"],"backgroundTag":"classloader-not-resettable","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}