docmirror/dev-sidecar · warning

插件【${key}】不可用,无法启动

Error message

插件【${key}】不可用,无法启动

What it means

Warning logged by the stub plugin's start() when someone tries to start a plugin that was registered as unavailable. The stub was created in expose.js because the real plugin module was null (e.g. free-eye missing in SEA builds). Calling start() is a no-op that only logs; calling run() on the stub throws '插件【key】不可用'.

Source

Thrown at packages/core/src/expose.js:41

  config.addDefault(key, pluginConfig)
  if (pluginStatus) {
    lodash.set(status, key, pluginStatus)
  }
  return api
}

const proxy = setupPlugin('proxy', modules.proxy, context, config)
const plugin = {}
for (const key in modules.plugin) {
  const target = modules.plugin[key]
  if (target == null) {
    // 插件不可用(如 SEA 独立可执行文件中无法携带 free-eye),注册为禁用状态
    log.warn(`插件【${key}】不可用,已注册为禁用状态`)
    const stub = {
      config: { key, enabled: false },
      status: { enabled: false },
      plugin: () => ({
        start: async () => log.warn(`插件【${key}】不可用,无法启动`),
        stop: async () => {},
        close: async () => {},
        run: async () => { throw new Error(`插件【${key}】不可用`) },
      }),
    }
    const stubApi = setupPlugin(`plugin.${key}`, stub, context, config)
    plugin[key] = stubApi
    continue
  }
  const api = setupPlugin(`plugin.${key}`, target, context, config)
  plugin[key] = api
}
config.resetDefault()
const server = modules.server
const serverStart = server.start

function newServerStart ({ mitmproxyPath }) {
  return serverStart({ mitmproxyPath, plugins: plugin })

View on GitHub (pinned to 7710cd56cc)

Solutions

  1. Don't start the plugin: check plugin availability/status first and skip start for plugins whose status.enabled is false.
  2. If you need free-eye, run the full install (normal Node deployment) instead of the SEA executable.
  3. If run() is required, expect it to throw '插件【key】不可用' — wrap in try/catch and treat as unsupported in this environment.
  4. Restore the missing plugin module/dependencies so expose.js registers the real plugin instead of the stub.

Example fix

// before
await DevSidecar.plugin.start('free-eye')
// after
const p = DevSidecar.plugin.get('free-eye')
if (p && p.status.enabled !== false) await DevSidecar.plugin.start('free-eye')
else console.warn('free-eye unavailable in this build')
Defensive patterns

Strategy: fallback

Validate before calling

const stub = DevSidecar.plugin?.get?.(key)
if (!stub || stub.status?.enabled === false) {
  console.warn(`plugin ${key} disabled/unavailable, not starting`)
  return
}

Type guard

function canStart(pluginEntry) {
  return pluginEntry != null && pluginEntry.status?.enabled !== false && typeof pluginEntry.plugin === 'function'
}

Try / catch

try {
  await plugin.start(key)
} catch (e) {
  if (/不可用|无法启动/.test(e.message)) {
    console.warn(`plugin ${key} unavailable in this build, continuing without it`)
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: Calling plugin.start(key) (or the GUI/plugin manager invoking start) for a plugin that was replaced by the unavailable-stub — typically free_eye after its module failed to load in a SEA executable or broken install.

Common situations: User toggles the free-eye (护眼) plugin on in the GUI while running the standalone SEA build; a script or automation tries to start all plugins indiscriminately; plugin state persisted from a previous full install is re-applied in an environment where the plugin no longer exists.

Related errors


AI-assisted analysis of docmirror/dev-sidecar@7710cd56cc (2026-08-31). Data as JSON: /api/errors/ba8b7c62611d0885. Report an issue: GitHub.