janhq/jan · error

MLX model appears to have crashed! Please reload!

Error message

MLX model appears to have crashed! Please reload!

What it means

The jan extension's chat() checks whether the local MLX server subprocess is still alive and responsive by hitting its /health endpoint. When the process is alive but the health fetch rejects (connection refused, timeout, reset socket), the model session is unloaded and this error is thrown, telling the user to reload the model.

Solutions

  1. Reload the model (unload then load again) to spawn a fresh MLX server session
  2. Check that no HTTP_PROXY/HTTPS_PROXY env vars intercept localhost and add localhost/127.0.0.1 to NO_PROXY
  3. Verify the session port is not occupied by another process and that the MLX server actually started
  4. Retry the request; transient health-check failures often clear on the next attempt

Example fix

// before
await chat(messages, model)
// after
try {
  await chat(messages, model)
} catch (e) {
  if (e.message.includes('crashed')) {
    await mlx.reload(model.id)
    await chat(messages, model)
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function isMlxHealthy(sessionInfo) {
  try {
    const res = await fetch(`http://127.0.0.1:${sessionInfo.port}/health`, { signal: AbortSignal.timeout(3000) })
    return res.ok
  } catch { return false }
}
if (!(await isMlxHealthy(sessionInfo))) await reloadModel(model.id)

Type guard

const isAlive = (s) => typeof s === 'object' && s !== null && typeof s.port === 'number' && s.port > 0

Try / catch

try {
  await chat(messages, model)
} catch (e) {
  if (String(e.message).includes('crashed')) {
    await reloadModel(model.id)
    return chat(messages, model)
  }
  throw e
}

Prevention

When it happens

Trigger: Calling chat() while the MLX server process is running but its HTTP health endpoint at http://localhost:<port>/health cannot be reached — e.g. the server just died, the port changed, or a firewall/proxy intercepts localhost requests.

Common situations: The MLX server crashed mid-session (OOM, bad model weights), the port recorded in sessionInfo is stale after a restart, a system proxy env var routes localhost through a proxy, or IPv6/IPv4 localhost resolution issues.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/4820bd60fe15f7f3. Report an issue: GitHub.

Appendix: source

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

    opts: chatCompletionRequest,
    abortController?: AbortController
  ): Promise<chatCompletion | AsyncIterable<chatCompletionChunk>> {
    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)
    }

View on GitHub (pinned to 7205d770c1)