{"record":{"id":"c66a80bdb2cee336","repo":"janhq/jan","slug":"model-already-loaded-c66a80","errorCode":null,"errorMessage":"Model already loaded!","messagePattern":"Model already loaded!","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extensions/mlx-extension/src/index.ts","lineNumber":246,"sourceCode":"\n  private async getRandomPort(): Promise<number> {\n    try {\n      return await invoke<number>('plugin:mlx|get_mlx_random_port')\n    } catch {\n      logger.error('Unable to find a suitable port for MLX server')\n      throw new Error('Unable to find a suitable port for MLX model')\n    }\n  }\n\n  override async load(\n    modelId: string,\n    overrideSettings?: any,\n    isEmbedding: boolean = false,\n    bypassAutoUnload: boolean = false\n  ): Promise<SessionInfo> {\n    const sInfo = await this.findSessionByModel(modelId)\n    if (sInfo) {\n      throw new Error('Model already loaded!')\n    }\n\n    if (this.loadingModels.has(modelId)) {\n      return this.loadingModels.get(modelId)!\n    }\n\n    const loadingPromise = this.performLoad(\n      modelId,\n      overrideSettings,\n      isEmbedding,\n      bypassAutoUnload\n    )\n    this.loadingModels.set(modelId, loadingPromise)\n\n    try {\n      return await loadingPromise\n    } finally {\n      this.loadingModels.delete(modelId)","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/extensions/mlx-extension/src/index.ts#L228-L264","documentation":"load() first checks findSessionByModel; if a session for that modelId already exists it throws 'Model already loaded!' instead of starting a duplicate server process. This is a deliberate guard against double-loading the same MLX model.","triggerScenarios":"Calling load(modelId) when the model is already running — e.g. clicking Load twice, loading from two UI surfaces, or a previous session that never unloaded (stale session record).","commonSituations":"Double-clicking load buttons, race between UI state and backend state after a crash that left a session record, or re-running a script that loads models without unloading first.","solutions":["Check whether the model is loaded first (findSessionByModel/sessionInfo) and reuse the existing session instead of calling load","Unload the existing session (unload(modelId)) before loading again if a fresh load is required","If the session is stale (process actually dead), clear stale session state/restart the app then retry","Guard call sites so load is only invoked when not already loaded/loading"],"exampleFix":"// before\nawait mlx.load(modelId)\n// after\nconst existing = await mlx.getSessionInfo(modelId)\nconst session = existing ?? (await mlx.load(modelId))","handlingStrategy":"try-catch","validationCode":"// Check before load\nconst existing = await mlx.getSessionInfo(modelId)\nif (existing) throw new Error(`${modelId} already loaded; reuse it`)","typeGuard":null,"tryCatchPattern":"try {\n  await mlx.load(modelId)\n} catch (e) {\n  if (!String(e).includes('Model already loaded')) throw e\n  // reuse existing session\n}","preventionTips":["Look up existing sessions before loading","Serialize load calls per modelId (single-flight) in UI code","Unload explicitly before intentional reloads","Clear stale session state after crashes before reloading"],"tags":["mlx","duplicate-load","state","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}