janhq/jan · error · Error

${e}

Error message

${e}

What it means

Thrown by getLoadedModels() when the invoke('plugin:llamacpp|get_loaded_models') IPC call rejects. The catch wraps the unknown rejection value via `throw new Error(e)` - note that when e is an Error instance, new Error(e) coerces it to a string like 'Error: <message>', and when e is a plain object the message becomes '[object Object]', losing detail. So this error is a generic 'the plugin IPC failed' wrapper.

Source

Thrown at extensions/llamacpp-extension/src/index.ts:3816

    await fs.rm(modelDir)

    try {
      await this.refreshRouterPreset()
    } catch (e) {
      logger.warn(`Router refresh after delete(${modelId}) failed:`, e)
    }
  }

  override async getLoadedModels(): Promise<string[]> {
    try {
      let models: string[] = await invoke<string[]>(
        'plugin:llamacpp|get_loaded_models'
      )
      return models
    } catch (e) {
      logger.error(e)
      throw new Error(e)
    }
  }

  /**
   * Check if mmproj.gguf file exists for a given model ID
   * @param modelId - The model ID to check for mmproj.gguf
   * @returns Promise<boolean> - true if mmproj.gguf exists, false otherwise
   */
  async checkMmprojExists(modelId: string): Promise<boolean> {
    try {
      const modelConfigPath = await joinPath([
        await this.getProviderPath(),
        'models',
        modelId,
        'model.yml',
      ])

      const modelConfig = await invoke<ModelConfig>('read_yaml', {

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Read logger.error output immediately before the throw for the raw rejection.
  2. Restart the app/router to re-register the plugin.
  3. Verify extension and plugin are the same version.
  4. Treat the failure as 'no models loaded' if your UI can tolerate it (don't block the user), but log it loudly.
  5. Fix the bug in this catch: use `throw new Error(e instanceof Error ? e.message : JSON.stringify(e))` so detail is preserved.

Example fix

// before - lose detail when e is an object
//   in source: throw new Error(e)
const m = await provider.getLoadedModels() // throws 'Error: <x>' or '[object Object]'
// after - caller tolerance + better error in source
let models: string[] = []
try { models = await provider.getLoadedModels() }
catch (e) { logger.warn('getLoadedModels failed, assuming empty:', e); models = [] }
// source-side fix:
//   throw new Error(e instanceof Error ? e.message : JSON.stringify(e))
Defensive patterns

Strategy: try-catch

Validate before calling

// Caller cannot validate plugin internals; degrade gracefully.
// Recommended: do not let getLoadedModels failure block the UI.
async function safeLoadedModels(provider: any): Promise<string[]> {
  try { return await provider.getLoadedModels() } catch { return [] }
}

Type guard

// Improve the source catch so detail survives.
function toError(e: unknown): Error {
  return e instanceof Error ? e : new Error(typeof e === 'string' ? e : JSON.stringify(e))
}

Try / catch

let models: string[] = []
try { models = await provider.getLoadedModels() }
catch (e) { logger.warn('getLoadedModels IPC failed, assuming empty:', e); models = [] }

Prevention

When it happens

Trigger: The llamacpp plugin is not registered or crashed. The Rust handler for get_loaded_models panicked. Router process died so the plugin cannot enumerate sessions. Tauri IPC serialization failure. Version skew between TS extension and Rust plugin.

Common situations: Calling getLoadedModels during shutdown when the plugin is being torn down. Router crashed mid-session and the plugin can no longer reach it. Development hot-reload broke plugin registration. Mismatched build artifacts after a partial update.

Related errors


AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12). Data as JSON: /api/errors/d71910b39c8b6e1d. Report an issue: GitHub.