janhq/jan · critical · Error

MLX model has crashed! Please reload!

Error message

MLX model has crashed! Please reload!

What it means

Thrown by chat() when is_mlx_process_running returns false — the OS reports the MLX server process is gone, i.e. it crashed or was killed externally. Unlike error 50 (process alive but unresponsive), here the process is definitively dead. The session entry is now orphaned; the caller must reload.

Source

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

    const sessionInfo = await this.findSessionByModel(opts.model)
    if (!sessionInfo) {
      throw new Error(`No active MLX session found for model: ${opts.model}`)
    }

    // Check if the process is alive
    const isAlive = await invoke<boolean>('plugin:mlx|is_mlx_process_running', {
      pid: sessionInfo.pid,
    })

    if (isAlive) {
      try {
        await fetch(`http://localhost:${sessionInfo.port}/health`)
      } catch (e) {
        this.unload(sessionInfo.model_id)
        throw new Error('MLX model appears to have crashed! Please reload!')
      }
    } else {
      throw new Error('MLX model has crashed! Please reload!')
    }

    const baseUrl = `http://localhost:${sessionInfo.port}/v1`
    const url = `${baseUrl}/chat/completions`
    const headers = {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${sessionInfo.api_key}`,
    }

    const body = JSON.stringify(opts)

    if (opts.stream) {
      return this.handleStreamingResponse(url, headers, body, abortController)
    }

    const response = await fetch(url, {
      method: 'POST',
      headers,

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Reload the model with engine.load(opts.model) to spawn a fresh server.
  2. If it repeatedly crashes, use a smaller ctx_size or a smaller model that fits GPU memory.
  3. Free GPU/system memory before reloading (close other GPU apps).
  4. Check system logs for the OOM/segfault cause.

Example fix

// before
const completion = await engine.chat(opts)

// after
try {
  return await engine.chat(opts)
} catch (e) {
  if (/has crashed/.test(String(e))) {
    await engine.unload(opts.model).catch(() => {})
    await engine.load(opts.model)
    return await engine.chat(opts)
  }
  throw e
}
Defensive patterns

Strategy: fallback

Validate before calling

import { invoke } from '@tauri-apps/api/core'

async function isMlxAlive(pid: number): Promise<boolean> {
  try { return await invoke<boolean>('plugin:mlx|is_mlx_process_running', { pid }) }
  catch { return false }
}

if (!(await isMlxAlive(sessionInfo.pid))) {
  await engine.load(opts.model) // respawn before chat
}

Try / catch

try {
  return await engine.chat(opts, abort)
} catch (e) {
  if (/has crashed/.test(String(e))) {
    await engine.unload(opts.model).catch(() => {})
    await engine.load(opts.model)
    return await engine.chat(opts, abort)
  }
  throw e
}

Prevention

When it happens

Trigger: MLX server segfaulted or was OOM-killed; user or another tool killed the pid; the process exited after a fatal Metal/runtime error; app resumed from sleep and the process did not survive.

Common situations: Out of memory on the GPU/system killed the server; a model too large for available memory crashed on first inference; system sleep/ resume orphaned the process; manual kill via Activity Monitor.

Related errors


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