agalwood/Motrix · error · AppError

PLUGIN_ACTIVATION_CAP_EXCEEDED

PLUGIN_ACTIVATION_CAP_EXCEEDED

Error message

active plugin cap (${this.maxActivePlugins}) reached

What it means

Activation is refused once the number of active plugins reaches maxActivePlugins (default 32, configurable via PluginHostOptions.maxActivePlugins), throwing PLUGIN_ACTIVATION_CAP_EXCEEDED. The cap bounds simultaneous VMs.

Source

Thrown at src/core/plugin/host/plugin-host.ts:236

    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()
    }

    const ffmpegSatisfied =
      ffmpegDetection.available &&
      ffmpegSatisfies(
        ffmpegDetection.version ?? '',

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Deactivate an idle or lower-priority plugin first, then retry activate.
  2. Wait for the idle sweep (5 min default) to reclaim VMs, or trigger it manually.
  3. Raise maxActivePlugins in PluginHostOptions if the environment can sustain more VMs.

Example fix

// before
await host.activate(id) // throws at cap
// after — make room first
if (host.activeCount >= host.maxActivePlugins) {
  const idle = host.pickIdlePlugin()
  if (idle) await host.deactivate(idle)
}
await host.activate(id)
Defensive patterns

Strategy: fallback

Validate before calling

function assertCapAvailable(activeCount: number, max: number): void {
  if (activeCount >= max) {
    throw new Error(`active plugin cap (${max}) reached; deactivate an idle plugin first`)
  }
}

Type guard

function hasCapRoom(activeCount: number, max: number): boolean {
  return activeCount < max
}

Try / catch

try {
  await host.activate(pluginId)
} catch (e) {
  if (e.code === 'PLUGIN_ACTIVATION_CAP_EXCEEDED') {
    const idle = host.pickIdlePlugin()
    if (idle) { await host.deactivate(idle); await host.activate(pluginId) }
    else throw e
  } else throw e
}

Prevention

When it happens

Trigger: Activating one more plugin while active.size is already >= maxActivePlugins.

Common situations: Many plugins enabled at once; cap lowered for a constrained environment; idle plugins not yet swept by the 5-min idle timer; a burst of concurrent activations.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/9980230513ff58a0. Report an issue: GitHub.