Tencent/matrix · error · RuntimeException
plugin stop, but plugin has been already destroyed
Error message
plugin stop, but plugin has been already destroyed
What it means
Thrown from Plugin.stop() when the plugin's status is PLUGIN_DESTROYED. A destroyed plugin has already released its listener and resources, so stop() cannot meaningfully run; this catches lifecycle sequences that stop a plugin after destroy (e.g. calling stop from a destroy path that has already torn the plugin down) and fails fast instead of notifying a dead listener.
Solutions
- Check plugin.isPluginDestroyed() before calling stop().
- Let Matrix's destroy path stop plugins; remove manual stop() calls in teardown.
- Use a single centralized shutdown routine to avoid duplicate stop/destroy calls.
Example fix
// before Matrix.with().destroy(); plugin.stop(); // after Matrix.with().destroy(); // stops plugins internally
Defensive patterns
Strategy: type-guard
Validate before calling
if (plugin.isPluginStarted() && !plugin.isPluginDestroyed()) {
plugin.stop();
} Type guard
boolean canStop(Plugin p) { return p.isPluginStarted() && !p.isPluginDestroyed(); } Try / catch
try {
plugin.stop();
} catch (RuntimeException e) {
Log.w(TAG, "plugin already destroyed", e);
} Prevention
- Do not call stop() after destroy()
- Centralize shutdown logic so stop/destroy is called once
- Check isPluginDestroyed() before lifecycle calls
When it happens
Trigger: Calling plugin.stop() after plugin.destroy(); Matrix destroy path also invokes stop, so a manual stop() after destroy() collides.
Common situations: Teardown code that calls both Matrix.with().destroy() and plugin.stop(); application exit handlers running twice; callbacks firing after destroy.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- plugin start, but plugin has been already destroyed
- plugin start, but plugin has been already started
- plugin start, plugin listener is null
- plugin stop, but plugin is never started
- plugin with tag is already exist
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/2a13bc01707611cd.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/plugin/Plugin.java:116
throw new RuntimeException("plugin start, but plugin has been already destroyed");
}
if (isPluginStarted()) {
throw new RuntimeException("plugin start, but plugin has been already started");
}
status = PLUGIN_STARTED;
if (pluginListener == null) {
throw new RuntimeException("plugin start, plugin listener is null");
}
pluginListener.onStart(this);
}
@Override
public void stop() {
if (isPluginDestroyed()) {
throw new RuntimeException("plugin stop, but plugin has been already destroyed");
}
if (!isPluginStarted()) {
throw new RuntimeException("plugin stop, but plugin is never started");
}
status = PLUGIN_STOPPED;
if (pluginListener == null) {
throw new RuntimeException("plugin stop, plugin listener is null");
}
pluginListener.onStop(this);
}
@Override
public void destroy() {
// stop first
if (isPluginStarted()) {View on GitHub (pinned to 3b8293bd65)