{"record":{"id":"27b4067d9d78b296","repo":"Tencent/matrix","slug":"plugin-stop-plugin-listener-is-null","errorCode":null,"errorMessage":"plugin stop, plugin listener is null","messagePattern":"plugin stop, plugin listener is null","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/plugin/Plugin.java","lineNumber":126,"sourceCode":"            throw new RuntimeException(\"plugin start, plugin listener is null\");\n        }\n        pluginListener.onStart(this);\n    }\n\n    @Override\n    public void stop() {\n        if (isPluginDestroyed()) {\n            throw new RuntimeException(\"plugin stop, but plugin has been already destroyed\");\n        }\n\n        if (!isPluginStarted()) {\n            throw new RuntimeException(\"plugin stop, but plugin is never started\");\n        }\n\n        status = PLUGIN_STOPPED;\n\n        if (pluginListener == null) {\n            throw new RuntimeException(\"plugin stop, plugin listener is null\");\n        }\n        pluginListener.onStop(this);\n    }\n\n    @Override\n    public void destroy() {\n        // stop first\n        if (isPluginStarted()) {\n            stop();\n        }\n        if (isPluginDestroyed()) {\n            throw new RuntimeException(\"plugin destroy, but plugin has been already destroyed\");\n        }\n        status = PLUGIN_DESTROYED;\n\n        if (pluginListener == null) {\n            throw new RuntimeException(\"plugin destroy, plugin listener is null\");\n        }","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/plugin/Plugin.java#L108-L144","documentation":"Plugin.stop() throws this when the plugin's pluginListener is null at stop time. Matrix plugins delegate lifecycle events (onStop) to a listener supplied via setPluginListener; calling stop() without one is an unrecoverable state, so the library fails fast with a RuntimeException.","triggerScenarios":"Calling plugin.stop() (directly or via destroy()/Matrix.onDestroy()) on a plugin that was constructed but never had setPluginListener() invoked with a non-null listener.","commonSituations":"Forgetting to register a listener when building a custom plugin; a listener registration call being skipped or conditional; clearing a listener reference manually before teardown; subclassing Plugin without wiring PluginListener in the Builder.","solutions":["Call plugin.setPluginListener(listener) after construction and before any lifecycle call","Guard stop() with a null check on the listener, or use Matrix's Builder which wires listeners automatically","Check plugin status before stopping; only stop plugins that went through start() with a listener attached","If you own the plugin subclass, override stop() to no-op when no listener is configured"],"exampleFix":"// before\nPlugin plugin = new MyPlugin();\nmatrix.addPlugin(plugin);\nplugin.stop();\n\n// after\nPlugin plugin = new MyPlugin();\nplugin.setPluginListener(new MyPluginListener());\nmatrix.addPlugin(plugin);\nplugin.stop();","handlingStrategy":"validation","validationCode":"if (plugin.getPluginListener() == null) {\n    plugin.setPluginListener(new MyPluginListener());\n}\nplugin.stop();","typeGuard":"if (plugin != null && plugin.getPluginListener() != null) { plugin.stop(); }","tryCatchPattern":"try {\n    plugin.stop();\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"listener is null\")) {\n        Log.w(TAG, \"plugin stop skipped: no listener\", e);\n    } else { throw e; }\n}","preventionTips":["Always register a PluginListener immediately after constructing a plugin","Use Matrix.Builder so listener wiring happens in one place","Never null out plugin listeners manually"],"tags":["android","lifecycle","null-listener","plugin"],"backgroundTag":"null-argument","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}