janhq/jan · warning · Error

Model already loaded!

Error message

Model already loaded!

What it means

Thrown by load() when findSessionByModel(modelId) already returns a session, meaning the model is currently loaded and serving. Loading it again would start a second server process on a new port and double GPU memory use, so the extension refuses. A separate loadingModels map handles concurrent in-flight loads.

Source

Thrown at extensions/mlx-extension/src/index.ts:216

  private async getRandomPort(): Promise<number> {
    try {
      return await invoke<number>('plugin:mlx|get_mlx_random_port')
    } catch {
      logger.error('Unable to find a suitable port for MLX server')
      throw new Error('Unable to find a suitable port for MLX model')
    }
  }

  override async load(
    modelId: string,
    overrideSettings?: any,
    isEmbedding: boolean = false,
    bypassAutoUnload: 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,
      overrideSettings,
      isEmbedding,
      bypassAutoUnload
    )
    this.loadingModels.set(modelId, loadingPromise)

    try {
      return await loadingPromise
    } finally {
      this.loadingModels.delete(modelId)

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Check engine.getLoadedModels()/findSessionByModel before calling load, and reuse the existing session.
  2. Call engine.unload(modelId) first if you genuinely need a fresh load with new settings.
  3. If the entry is stale (process actually dead), run unload to clear it, then load.

Example fix

// before
await engine.load(modelId, overrideSettings)

// after
const existing = await engine.findSessionByModel(modelId)
if (existing) {
  // reuse, or unload first if overrideSettings require a reload
  return existing
}
await engine.load(modelId, overrideSettings)
Defensive patterns

Strategy: validation

Validate before calling

const existing = await engine.findSessionByModel(modelId).catch(() => null)
if (existing) {
  // already loaded; reuse or unload first
  return existing
}
await engine.load(modelId)

Try / catch

try {
  await engine.load(modelId, overrideSettings)
} catch (e) {
  if (/Model already loaded/.test(String(e))) {
    return // acceptable: nothing to do
  }
  throw e
}

Prevention

When it happens

Trigger: Calling engine.load(modelId) twice without an intervening unload(); a chat thread already loaded the model and a second UI action triggers another load; the session registry was not cleared after a crash so findSessionByModel returns a stale entry.

Common situations: Race between two 'start chat' actions; model auto-loaded on app start and a manual load is also issued; a previous crash left a zombie session entry that findSessionByModel still finds.

Related errors


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