{"record":{"id":"c8ca9eaec6ed9be4","repo":"jenkinsci/jenkins","slug":"doesn-t-extend-from-hudson-plugin","errorCode":null,"errorMessage":"{} doesn't extend from hudson.Plugin","messagePattern":"(.+?) doesn't extend from hudson\\.Plugin","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/hudson/ClassicPluginStrategy.java","lineNumber":387,"sourceCode":"    }\n\n    @Override\n    public void load(PluginWrapper wrapper) throws IOException {\n        // override the context classloader. This no longer makes sense,\n        // but it is left for the backward compatibility\n        ClassLoader old = Thread.currentThread().getContextClassLoader();\n        Thread.currentThread().setContextClassLoader(wrapper.classLoader);\n        try {\n            String className = wrapper.getPluginClass();\n            if (className == null) {\n                // use the default dummy instance\n                wrapper.setPlugin(new DummyImpl());\n            } else {\n                try {\n                    Class<?> clazz = wrapper.classLoader.loadClass(className);\n                    Object o = clazz.getDeclaredConstructor().newInstance();\n                    if (!(o instanceof Plugin)) {\n                        throw new IOException(className + \" doesn't extend from hudson.Plugin\");\n                    }\n                    wrapper.setPlugin((Plugin) o);\n                } catch (LinkageError | ClassNotFoundException e) {\n                    throw new IOException(\"Unable to load \" + className + \" from \" + wrapper.getShortName(), e);\n                } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {\n                    throw new IOException(\"Unable to create instance of \" + className + \" from \" + wrapper.getShortName(), e);\n                }\n            }\n\n            // initialize plugin\n            try {\n                Plugin plugin = wrapper.getPluginOrFail();\n                plugin.setServletContext(pluginManager.context);\n                startPlugin(wrapper);\n            } catch (Throwable t) {\n                // gracefully handle any error in plugin.\n                throw new IOException(\"Failed to initialize\", t);\n            }","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/jenkinsci/jenkins/blob/2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc/core/src/main/java/hudson/ClassicPluginStrategy.java#L369-L405","documentation":"IOException thrown during plugin instantiation when the plugin class named in the manifest loads and instantiates successfully but the resulting object is not an instance of hudson.Plugin. Jenkins requires the declared plugin class to extend hudson.Plugin so its lifecycle can be managed.","triggerScenarios":"A plugin manifest's Plugin-Class attribute points at a class that does not extend hudson.Plugin (e.g. a utility class, a Jelly-bound object, or a class extending jenkins.model.Jenkins by mistake).","commonSituations":"Plugin developer set Plugin-Class to the wrong class; refactored the main plugin class to no longer extend Plugin; copied a manifest from another plugin without updating Plugin-Class.","solutions":["Make the class referenced by the manifest Plugin-Class extend hudson.Plugin (or remove the Plugin-Class attribute to use the default DummyImpl).","If the plugin has no lifecycle need, delete the Plugin-Class entry from the manifest instead of pointing at a non-Plugin class.","Rebuild and reinstall the plugin after the change."],"exampleFix":"// before\npublic class MyPlugin {\n  ...\n}\n// after\nimport hudson.Plugin;\npublic class MyPlugin extends Plugin {\n  ...\n}","handlingStrategy":"type-guard","validationCode":"Class<?> clazz = wrapper.classLoader.loadClass(className);\nif (!Plugin.class.isAssignableFrom(clazz)) {\n    throw new IOException(className + \" must extend hudson.Plugin\");\n}","typeGuard":"boolean isPluginClass(Class<?> c) {\n    return c != null && hudson.Plugin.class.isAssignableFrom(c);\n}","tryCatchPattern":"try {\n    Object o = clazz.getDeclaredConstructor().newInstance();\n    if (!(o instanceof Plugin)) {\n        // instruct plugin author to extend hudson.Plugin\n    }\n} catch (IOException e) {\n    // report the manifest Plugin-Class value\n}","preventionTips":["Make the Plugin-Class extend hudson.Plugin, or omit the attribute.","Add a unit test asserting the plugin class is a Plugin subclass.","Review the manifest Plugin-Class after refactoring the main class."],"tags":["jenkins","plugin-loading","lifecycle","class-type"],"backgroundTag":null,"analyzedSha":"2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc","analyzedAt":"2026-08-14T07:07:15.274Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}