{"record":{"id":"9b3e61efd71e321e","repo":"halo-dev/halo","slug":"failed-to-load-class-s-for-plugin-s","errorCode":null,"errorMessage":"Failed to load class %s for plugin %s.","messagePattern":"Failed to load class (.+?) for plugin (.+?)\\.","errorType":"exception","errorClass":"PluginRuntimeException","httpStatus":null,"severity":"critical","filePath":"application/src/main/java/run/halo/app/plugin/DefaultPluginApplicationContextFactory.java","lineNumber":156,"sourceCode":"        rootContext.getBeanProvider(PluginRouterFunctionRegistry.class).ifUnique(registry -> {\n            var pluginRouterFunctionManager = new PluginRouterFunctionManager(registry);\n            beanFactory.registerSingleton(\"pluginRouterFunctionManager\", pluginRouterFunctionManager);\n        });\n\n        rootContext\n                .getBeanProvider(SearchService.class)\n                .ifUnique(searchService -> beanFactory.registerSingleton(\"searchService\", searchService));\n\n        sw.stop();\n\n        sw.start(\"LoadComponents\");\n        var classNames = pluginManager.getExtensionClassNames(pluginId);\n        classNames.stream()\n                .map(className -> {\n                    try {\n                        return classLoader.loadClass(className);\n                    } catch (ClassNotFoundException e) {\n                        throw new PluginRuntimeException(String.format(\"\"\"\n                        Failed to load class %s for plugin %s.\\\n                        \"\"\", className, pluginId), e);\n                    }\n                })\n                .forEach(clazzName -> context.registerBean(clazzName));\n        sw.stop();\n        log.debug(\"Created application context for plugin {}\", pluginId);\n\n        log.debug(\"Refreshing application context for plugin {}\", pluginId);\n        sw.start(\"Refresh\");\n\n        // Set the context ClassLoader to the plugin ClassLoader to ensure that\n        // any class loading operations performed by the context (e.g., initializing\n        // bean definitions, loading class resources during static initialization)\n        // use the correct ClassLoader.\n        var previous = Thread.currentThread().getContextClassLoader();\n        try {\n            Thread.currentThread().setContextClassLoader(classLoader);","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/plugin/DefaultPluginApplicationContextFactory.java#L138-L174","documentation":"Thrown as PluginRuntimeException during DefaultPluginApplicationContextFactory when classLoader.loadClass(className) throws ClassNotFoundException for one of the plugin's extension class names reported by pluginManager.getExtensionClassNames(pluginId). Halo tries to load each declared extension class while building the plugin's application context; a missing class aborts plugin startup.","triggerScenarios":"A plugin JAR whose extension class list (declared via SPI/extension manifest) references a class not present in the plugin classloader: renamed/removed class, shaded relocation mismatch, dependency class not packaged, or version skew between plugin build and runtime API.","commonSituations":"Plugin rebuilt against a different Halo API version; refactored/renamed extension class not reflected in the manifest; missing optional dependency packaged only at compile time; corrupted/incomplete JAR; plugin built for an older/newer core than installed.","solutions":["Rebuild the plugin against the currently installed Halo version and repackage.","Ensure the extension manifest (class names) matches the actual classes in the JAR.","Verify all required dependencies are shaded/packaged into the plugin JAR.","Reinstall the plugin JAR cleanly (remove the old copy) and restart."],"exampleFix":"# before\n# plugin manifest lists run.example.OldExtension which was renamed\n\n# after\n# update plugin manifest to run.example.NewExtension and rebuild:\n./gradlew clean build\n# redeploy build/libs/*.jar","handlingStrategy":"try-catch","validationCode":"// Validate the plugin JAR's declared extension classes against its entries before install\nfor (String cn : pluginManager.getExtensionClassNames(pluginId)) {\n    if (!jarEntries.contains(cn.replace('.', '/') + \".class\")) {\n        throw new IllegalStateException(\"Plugin declares missing class: \" + cn);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    factory.createApplicationContext(pluginId);\n} catch (PluginRuntimeException e) {\n    log.error(\"Failed to start plugin {} (class load failed); reinstall against this Halo version\", pluginId, e);\n    disablePlugin(pluginId);\n}","preventionTips":["Build plugins against the exact installed Halo API version.","Keep the extension manifest in sync with the actual classes.","Shade required dependencies into the plugin JAR.","Reinstall plugins cleanly after a Halo major upgrade."],"tags":["plugin","classloader","startup","plugin-context"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}