janhq/jan · error · Error

Unable to find a suitable port for MLX model

Error message

Unable to find a suitable port for MLX model

What it means

Thrown by getRandomPort() when the Tauri command plugin:mlx|get_mlx_random_port rejects. The MLX extension delegates port allocation to the Rust plugin, which scans for a free TCP port; if it cannot find one or the command itself errors, no port is available to start the MLX server. Note the log line says 'MLX server' while the thrown message says 'MLX model' — same cause.

Source

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

        id: modelId,
        name: modelConfig.name ?? modelId,
        providerId: this.provider,
        port: 0,
        sizeBytes: modelConfig.size_bytes ?? 0,
        embedding: modelConfig.embedding ?? false,
        capabilities: capabilities.length > 0 ? capabilities : undefined,
      } as modelInfo)
    }

    return modelInfos
  }

  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)!
    }

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Free up ephemeral ports (stop other local servers) and retry load().
  2. Verify the mlx Tauri plugin is correctly registered and its permissions allow get_mlx_random_port.
  3. Restart the app to reset plugin state.
  4. Check the plugin's Rust logs for the underlying bind error (EACCES, EADDRINUSE).

Example fix

// before
const port = await this.getRandomPort()

// after
let port: number
try {
  port = await this.getRandomPort()
} catch (e) {
  logger.error('No free port for MLX; ask user to free ports', e)
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function canBindPort(): Promise<boolean> {
  try {
    const p = await invoke<number>('plugin:mlx|get_mlx_random_port')
    return typeof p === 'number' && p > 0
  } catch { return false }
}

Try / catch

try {
  return await engine.load(modelId, overrideSettings, isEmbedding)
} catch (e) {
  if (/suitable port for MLX/.test(String(e))) {
    await delay(1000) // let ports free up, retry once
    return await engine.load(modelId, overrideSettings, isEmbedding)
  }
  throw e
}

Prevention

When it happens

Trigger: Heavy port exhaustion (many dev servers/proxies occupying ephemeral range); the MLX Tauri plugin not registered or failed to init; OS-level restrictions on binding; ephemeral port range narrowed.

Common situations: Developer machine running many local services; a firewall/sandbox blocking bind; plugin permission scope missing in tauri.conf; plugin build mismatch after an app upgrade.

Related errors


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