{"record":{"id":"d71910b39c8b6e1d","repo":"janhq/jan","slug":"e","errorCode":null,"errorMessage":"${e}","messagePattern":"\\$\\{e\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":3816,"sourceCode":"\n    await fs.rm(modelDir)\n\n    try {\n      await this.refreshRouterPreset()\n    } catch (e) {\n      logger.warn(`Router refresh after delete(${modelId}) failed:`, e)\n    }\n  }\n\n  override async getLoadedModels(): Promise<string[]> {\n    try {\n      let models: string[] = await invoke<string[]>(\n        'plugin:llamacpp|get_loaded_models'\n      )\n      return models\n    } catch (e) {\n      logger.error(e)\n      throw new Error(e)\n    }\n  }\n\n  /**\n   * Check if mmproj.gguf file exists for a given model ID\n   * @param modelId - The model ID to check for mmproj.gguf\n   * @returns Promise<boolean> - true if mmproj.gguf exists, false otherwise\n   */\n  async checkMmprojExists(modelId: string): Promise<boolean> {\n    try {\n      const modelConfigPath = await joinPath([\n        await this.getProviderPath(),\n        'models',\n        modelId,\n        'model.yml',\n      ])\n\n      const modelConfig = await invoke<ModelConfig>('read_yaml', {","sourceCodeStart":3798,"sourceCodeEnd":3834,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/llamacpp-extension/src/index.ts#L3798-L3834","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read logger.error output immediately before the throw for the raw rejection.","Restart the app/router to re-register the plugin.","Verify extension and plugin are the same version.","Treat the failure as 'no models loaded' if your UI can tolerate it (don't block the user), but log it loudly.","Fix the bug in this catch: use `throw new Error(e instanceof Error ? e.message : JSON.stringify(e))` so detail is preserved."],"exampleFix":"// before - lose detail when e is an object\n//   in source: throw new Error(e)\nconst m = await provider.getLoadedModels() // throws 'Error: <x>' or '[object Object]'\n// after - caller tolerance + better error in source\nlet models: string[] = []\ntry { models = await provider.getLoadedModels() }\ncatch (e) { logger.warn('getLoadedModels failed, assuming empty:', e); models = [] }\n// source-side fix:\n//   throw new Error(e instanceof Error ? e.message : JSON.stringify(e))","handlingStrategy":"try-catch","validationCode":"// Caller cannot validate plugin internals; degrade gracefully.\n// Recommended: do not let getLoadedModels failure block the UI.\nasync function safeLoadedModels(provider: any): Promise<string[]> {\n  try { return await provider.getLoadedModels() } catch { return [] }\n}","typeGuard":"// Improve the source catch so detail survives.\nfunction toError(e: unknown): Error {\n  return e instanceof Error ? e : new Error(typeof e === 'string' ? e : JSON.stringify(e))\n}","tryCatchPattern":"let models: string[] = []\ntry { models = await provider.getLoadedModels() }\ncatch (e) { logger.warn('getLoadedModels IPC failed, assuming empty:', e); models = [] }","preventionTips":["Keep extension and plugin versions in sync.","Restart the app after a plugin/router crash before re-querying loaded models.","Fix the source: throw new Error(e instanceof Error ? e.message : JSON.stringify(e)) so callers see real detail.","Don't let a transient IPC failure hard-stop the UI - degrade to an empty list with a warning."],"tags":["ipc","plugin","tauri","rust","loaded-models","error-wrapping"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}