{"record":{"id":"8d5d2eddc0937bca","repo":"Tencent/matrix","slug":"plugin-start-but-plugin-has-been-already-destroye","errorCode":null,"errorMessage":"plugin start, but plugin has been already destroyed","messagePattern":"plugin start, but plugin has been already destroyed","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":98,"sourceCode":"            content.put(Issue.ISSUE_REPORT_TIME, System.currentTimeMillis());\n\n        } catch (JSONException e) {\n            MatrixLog.e(TAG, \"json error\", e);\n        }\n\n        //MatrixLog.e(TAG, \"detect issue:%s\", issue);\n        pluginListener.onReportIssue(issue);\n    }\n\n    @Override\n    public Application getApplication() {\n        return application;\n    }\n\n    @Override\n    public void start() {\n        if (isPluginDestroyed()) {\n            throw new RuntimeException(\"plugin start, but plugin has been already destroyed\");\n        }\n\n        if (isPluginStarted()) {\n            throw new RuntimeException(\"plugin start, but plugin has been already started\");\n        }\n\n        status = PLUGIN_STARTED;\n\n        if (pluginListener == null) {\n            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\");","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/plugin/Plugin.java#L80-L116","documentation":"Thrown from Plugin.start() when the plugin's internal status is PLUGIN_DESTROYED. Once a plugin has been destroyed its resources and listener wiring are torn down, so restarting it is not supported; any lifecycle orchestration that calls start() after destroy() indicates a programming error in the host app or Matrix itself and is rejected with this RuntimeException.","triggerScenarios":"Calling plugin.start() after plugin.destroy() / Matrix.with().destroy() (or onDestroy lifecycle callback).","commonSituations":"Restart logic that calls start after teardown; keeping stale plugin references after Matrix destroy and reusing them; foreground/background listeners restarting destroyed plugins.","solutions":["Re-create the plugin instance (and its Matrix) after destroy instead of calling start on the old one.","Check plugin.isPluginDestroyed() before calling start().","Do not destroy plugins you intend to stop/start again — use stop() instead."],"exampleFix":"// before\nplugin.destroy();\nplugin.start();\n// after\nplugin.destroy();\nPlugin plugin = new MyPlugin();\nplugin.init(app, listener);\nplugin.start();","handlingStrategy":"type-guard","validationCode":"if (!plugin.isPluginDestroyed()) {\n    plugin.start();\n}","typeGuard":"boolean canStart(Plugin p) { return !p.isPluginDestroyed() && !p.isPluginStarted(); }","tryCatchPattern":"try {\n    plugin.start();\n} catch (RuntimeException e) {\n    Log.e(TAG, \"cannot start destroyed plugin\", e);\n}","preventionTips":["Never reuse plugin references after destroy()","Use stop() for temporary suspension, destroy() only for final teardown","Rebuild the whole Matrix (and plugins) after destroy"],"tags":["android","plugins","lifecycle"],"backgroundTag":"invalid-state-transition","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"}