agalwood/Motrix · error · AppError
PLUGIN_RUNTIME_FAULT
PLUGIN_RUNTIME_FAULT
Error message
plugin ${pluginId} is disabled What it means
The plugin is indexed in the registry but its state.enabled flag is false, so activation is refused with PLUGIN_RUNTIME_FAULT. Disabled plugins cannot be activated until re-enabled.
Source
Thrown at src/core/plugin/host/plugin-host.ts:230
const inFlight = this.activating.get(pluginId)
if (inFlight) return inFlight
const promise = this.doActivate(pluginId).finally(() => {
this.activating.delete(pluginId)
})
this.activating.set(pluginId, promise)
return promise
}
private async doActivate(pluginId: string): Promise<void> {
const indexed = this.opts.registry.get(pluginId)
if (!indexed) {
throw new AppError(
ErrorCode.PluginManifestInvalid,
`unknown plugin: ${pluginId}`
)
}
if (!indexed.state.enabled) {
throw new AppError(
ErrorCode.PluginRuntimeFault,
`plugin ${pluginId} is disabled`
)
}
if (this.active.size >= this.maxActivePlugins) {
throw new AppError(
ErrorCode.PluginActivationCapExceeded,
`active plugin cap (${this.maxActivePlugins}) reached`
)
}
const needsFfmpeg =
indexed.manifest.permissions.includes('ffmpeg') ||
(indexed.manifest.optionalPermissions ?? []).includes('ffmpeg')
let ffmpegDetection: FfmpegDetection = { available: false }
if (needsFfmpeg && this.opts.ffmpegDetect) {
ffmpegDetection = await this.opts.ffmpegDetect()View on GitHub (pinned to 1a708ee577)
Solutions
- Check indexed.state.enabled before activating and prompt the user to enable if false.
- Inspect stateStore/registry for the recorded error that caused the auto-disable and fix the root cause first.
- Call the registry enable path (re-grant consent if required) before retrying activate.
Example fix
// before
await host.activate(id) // throws if disabled
// after
const st = host.registry.get(id)
if (!st?.state.enabled) {
await host.registry.enable(id) // may require consent
}
await host.activate(id) Defensive patterns
Strategy: validation
Validate before calling
function assertPluginEnabled(pluginId: string, registry: { get(id: string): { state: { enabled: boolean } } | undefined }): void {
const entry = registry.get(pluginId)
if (!entry?.state.enabled) {
throw new Error(`plugin ${pluginId} is disabled; enable it (and grant consent) before activating`)
}
} Type guard
function isPluginEnabled(entry: { state: { enabled: boolean } } | undefined): entry is { state: { enabled: true } } {
return !!entry && entry.state.enabled === true
} Try / catch
try {
await host.activate(pluginId)
} catch (e) {
if (e.code === 'PLUGIN_RUNTIME_FAULT' && /disabled/.test(e.message)) {
// inspect stateStore for the recorded error, fix root cause, then enable + retry
} else throw e
} Prevention
- Check state.enabled before activating and prompt for consent/enable.
- Inspect recorded errors that auto-disabled the plugin and fix the root cause first.
- Do not retry activate in a tight loop after a disable; re-enable explicitly.
When it happens
Trigger: User disabled the plugin; the host auto-disabled it after a prior error (stateStore.recordError + refreshState); consent/grant was never given; policy disabled it.
Common situations: Prior activation/ffmpeg/signature error auto-disabled the plugin; user toggled it off in UI; consent flow not completed; grants revoked.
Related errors
- PluginActivationCapExceeded
- PLUGIN_MANIFEST_INVALID
- PLUGIN_ACTIVATION_CAP_EXCEEDED
- plugin.lifecycle.activation_capability_violation
- PluginManifestInvalid
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/88f82cf9d4e711b5.
Report an issue: GitHub.