janhq/jan · error · Error
Model already loaded!!
Error message
Model already loaded!!
What it means
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.
Source
Thrown at extensions/llamacpp-extension/src/index.ts:3432
if (
cleanKey &&
valueParts.length > 0 &&
!cleanKey.startsWith('LLAMA')
) {
target[cleanKey] = valueParts.join('=').trim()
}
})
}
override async load(
modelId: string,
_settings?: unknown,
isEmbedding: boolean = false
): Promise<SessionInfo> {
const sInfo = await this.findSessionByModel(modelId)
if (sInfo) {
throw new Error('Model already loaded!!')
}
if (this.loadingModels.has(modelId)) {
return this.loadingModels.get(modelId)!
}
const loadingPromise = this.performLoad(modelId, isEmbedding)
this.loadingModels.set(modelId, loadingPromise)
try {
return await loadingPromise
} finally {
this.loadingModels.delete(modelId)
}
}
// Awaits the deferred startup, then makes one direct attempt if the router
// still isn't up. Safe to call redundantly: startRouter reuses a router thatView on GitHub (pinned to fad3f12a14)
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.
Example fix
// before
await provider.load('qwen'); await provider.load('qwen') // second throws
// after - guard with state check
const loaded = await provider.getLoadedModels()
if (!loaded.includes('qwen')) await provider.load('qwen')
// or treat already-loaded as success:
try { await provider.load('qwen') }
catch (e) { if (!/already loaded/.test(String(e))) throw e } Defensive patterns
Strategy: validation
Validate before calling
// Avoid double-load: only load if not already in a session
const loaded = await provider.getLoadedModels()
if (loaded.includes(modelId)) {
// already loaded - treat as success, or unload first to force a reload
return
}
await provider.load(modelId) Type guard
async function isModelLoaded(provider: { getLoadedModels(): Promise<string[]> }, id: string): Promise<boolean> {
return (await provider.getLoadedModels()).includes(id)
} Try / catch
try { await provider.load(modelId) }
catch (e) {
if (/already loaded/.test(String(e))) return // model is loaded - fine
throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- No active session found for model: ${modelId}
- Model ${modelId} already exists
- ${String(e)}
- Model ${modelId} does not exist
- Model with ID ${model.id} already exists
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/fe53391a59e47dca.
Report an issue: GitHub.