docmirror/dev-sidecar · warning

插件【${key}】不可用,已注册为禁用状态

Error message

插件【${key}】不可用,已注册为禁用状态

What it means

Warning logged in expose.js during startup when a plugin module from modules.plugin resolved to null/undefined. This happens because the getter for a plugin (e.g. free_eye) failed to load and returned null (commonly in SEA single-executable builds where the ESM free-eye module cannot be bundled). The core registers a disabled stub plugin in its place so the app still starts: its config/status are enabled:false and start/stop are no-ops.

Source

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

function setupPlugin (key, plugin, context, config) {
  const pluginConfig = plugin.config
  const PluginClass = plugin.plugin
  const pluginStatus = plugin.status
  const api = PluginClass(context)
  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()

View on GitHub (pinned to 7710cd56cc)

Solutions

  1. If you don't need the plugin (e.g. free-eye in a headless/SEA build), ignore the warning — behavior is intentional and safe.
  2. If you need it, run from a normal Node install (pnpm install at repo root) rather than the SEA executable so the ESM module is present.
  3. Verify packages/core/src/modules/plugin/free-eye exists and its dependencies are installed; reinstall/repair the package if missing.
  4. If a custom plugin getter returns null, fix the underlying require() error (check logs for the companion '加载 free-eye 插件失败' message with e.message).
Defensive patterns

Strategy: fallback

Validate before calling

const mod = DevSidecar.modules?.plugin?.[key]
if (mod == null) {
  console.warn(`plugin ${key} unavailable, skipping registration/start`)
}

Type guard

function isPluginAvailable(mod) {
  return mod != null && typeof mod === 'object' && mod.plugin != null
}

Try / catch

try {
  await plugin.start(key)
} catch (e) {
  if (/不可用/.test(e.message)) console.warn(`plugin ${key} unavailable, ignored:`, e.message)
  else throw e
}

Prevention

When it happens

Trigger: Application startup (expose.js module init) with a plugin key whose module getter returned null — specifically the free_eye getter in modules/plugin/index.js catching a require() failure, e.g. running from a Node SEA build where ./free-eye (ESM) cannot be required.

Common situations: Running the dev-sidecar SEA standalone executable where free-eye is not packaged; a broken install where the free-eye directory/dependencies are missing; a module that throws at require-time due to a syntax/dependency error, silently degrading the plugin to disabled.

Related errors


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