{"record":{"id":"fe53391a59e47dca","repo":"janhq/jan","slug":"model-already-loaded","errorCode":null,"errorMessage":"Model already loaded!!","messagePattern":"Model already loaded!!","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":3432,"sourceCode":"\n        if (\n          cleanKey &&\n          valueParts.length > 0 &&\n          !cleanKey.startsWith('LLAMA')\n        ) {\n          target[cleanKey] = valueParts.join('=').trim()\n        }\n      })\n  }\n\n  override async load(\n    modelId: string,\n    _settings?: unknown,\n    isEmbedding: 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(modelId, isEmbedding)\n    this.loadingModels.set(modelId, loadingPromise)\n\n    try {\n      return await loadingPromise\n    } finally {\n      this.loadingModels.delete(modelId)\n    }\n  }\n\n  // Awaits the deferred startup, then makes one direct attempt if the router\n  // still isn't up. Safe to call redundantly: startRouter reuses a router that","sourceCodeStart":3414,"sourceCodeEnd":3450,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/llamacpp-extension/src/index.ts#L3414-L3450","documentation":"Thrown by load() at the very top when findSessionByModel(modelId) returns a non-null SessionInfo - i.e. the llama.cpp router already reports an active session for this modelId. load() is designed to be idempotent-ish: a concurrent second load of the same model joins the in-flight promise (loadingModels map) rather than starting a duplicate, but a second load of an already-LOADED model is a hard error instead of a silent no-op, to surface UI/logic bugs that double-load.","triggerScenarios":"Calling load('qwen') twice in succession without an unload in between. Two UI actions (e.g. chat + embed bootstrap) both call load on the same id. The router was not aware the model was unloaded (stale session). Loading an embedding model that's already loaded as a chat model under the same id.","commonSituations":"App startup races between the embedder bootstrap and the user's first chat. Hot-reload during development re-invokes load. A 'switch model' flow forgot to unload the previous one. Router restart didn't clear the session table so findSessionByModel still returns the old session.","solutions":["Before calling load, check if the model is already loaded (findSessionByModel or getLoadedModels) and skip or unload first.","Call unload(modelId) before re-loading if you intend to reload with new settings.","If you don't know the state, wrap load in a try/catch that, on 'Model already loaded', treats it as success (the model IS loaded).","Audit the caller for duplicate load invocations triggered by UI event races."],"exampleFix":"// before\nawait provider.load('qwen'); await provider.load('qwen') // second throws\n// after - guard with state check\nconst loaded = await provider.getLoadedModels()\nif (!loaded.includes('qwen')) await provider.load('qwen')\n// or treat already-loaded as success:\ntry { await provider.load('qwen') }\ncatch (e) { if (!/already loaded/.test(String(e))) throw e }","handlingStrategy":"validation","validationCode":"// Avoid double-load: only load if not already in a session\nconst loaded = await provider.getLoadedModels()\nif (loaded.includes(modelId)) {\n  // already loaded - treat as success, or unload first to force a reload\n  return\n}\nawait provider.load(modelId)","typeGuard":"async function isModelLoaded(provider: { getLoadedModels(): Promise<string[]> }, id: string): Promise<boolean> {\n  return (await provider.getLoadedModels()).includes(id)\n}","tryCatchPattern":"try { await provider.load(modelId) }\ncatch (e) {\n  if (/already loaded/.test(String(e))) return // model is loaded - fine\n  throw e\n}","preventionTips":["Maintain a single source of truth for 'loaded models' in the UI and guard load against it.","Reload via unload->load rather than load->load.","After a router restart, refresh the loaded list before issuing load calls."],"tags":["model","load","session","state","duplicate"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}