{"record":{"id":"f80cbdae7fd1ac03","repo":"janhq/jan","slug":"unable-to-find-a-suitable-port-for-mlx-model","errorCode":null,"errorMessage":"Unable to find a suitable port for MLX model","messagePattern":"Unable to find a suitable port for MLX model","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/mlx-extension/src/index.ts","lineNumber":204,"sourceCode":"        id: modelId,\n        name: modelConfig.name ?? modelId,\n        providerId: this.provider,\n        port: 0,\n        sizeBytes: modelConfig.size_bytes ?? 0,\n        embedding: modelConfig.embedding ?? false,\n        capabilities: capabilities.length > 0 ? capabilities : undefined,\n      } as modelInfo)\n    }\n\n    return modelInfos\n  }\n\n  private async getRandomPort(): Promise<number> {\n    try {\n      return await invoke<number>('plugin:mlx|get_mlx_random_port')\n    } catch {\n      logger.error('Unable to find a suitable port for MLX server')\n      throw new Error('Unable to find a suitable port for MLX model')\n    }\n  }\n\n  override async load(\n    modelId: string,\n    overrideSettings?: any,\n    isEmbedding: boolean = false,\n    bypassAutoUnload: boolean = false\n  ): Promise<SessionInfo> {\n    const sInfo = await this.findSessionByModel(modelId)\n    if (sInfo) {\n      throw new Error('Model already loaded!')\n    }\n\n    if (this.loadingModels.has(modelId)) {\n      return this.loadingModels.get(modelId)!\n    }\n","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/mlx-extension/src/index.ts#L186-L222","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Free up ephemeral ports (stop other local servers) and retry load().","Verify the mlx Tauri plugin is correctly registered and its permissions allow get_mlx_random_port.","Restart the app to reset plugin state.","Check the plugin's Rust logs for the underlying bind error (EACCES, EADDRINUSE)."],"exampleFix":"// before\nconst port = await this.getRandomPort()\n\n// after\nlet port: number\ntry {\n  port = await this.getRandomPort()\n} catch (e) {\n  logger.error('No free port for MLX; ask user to free ports', e)\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"async function canBindPort(): Promise<boolean> {\n  try {\n    const p = await invoke<number>('plugin:mlx|get_mlx_random_port')\n    return typeof p === 'number' && p > 0\n  } catch { return false }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await engine.load(modelId, overrideSettings, isEmbedding)\n} catch (e) {\n  if (/suitable port for MLX/.test(String(e))) {\n    await delay(1000) // let ports free up, retry once\n    return await engine.load(modelId, overrideSettings, isEmbedding)\n  }\n  throw e\n}","preventionTips":["Free ephemeral ports before loading MLX models.","Confirm the mlx Tauri plugin and its permissions are registered.","Restart the app if the plugin fails to initialize."],"tags":["network","port-allocation","tauri-plugin","mlx","typescript"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}