libnyanpasu/clash-nyanpasu · error
Port {} is not available
Error message
Port {} is not available What it means
With ExternalControllerPortStrategy::Fixed, get_clash_external_port requires the configured port to be free; if local_port_available reports it occupied, it bails with this message. The function refuses to silently pick another port under a fixed strategy.
Source
Thrown at backend/tauri/src/utils/help.rs:164
Ok(())
}
/// Resolve the UI language from the OS locale, as the canonical i18n key.
///
/// The key names a `rust_i18n` bundle in `backend/tauri/locales` and a paraglide
/// locale in the frontend; both use the same lowercase spelling.
pub fn detect_system_i18n_key() -> &'static str {
nyanpasu_config::application::default_i18n_language().as_str()
}
pub fn get_clash_external_port(
strategy: &ExternalControllerPortStrategy,
port: u16,
) -> anyhow::Result<u16> {
match strategy {
ExternalControllerPortStrategy::Fixed => {
if !port_scanner::local_port_available(port) {
bail!("Port {} is not available", port);
}
}
ExternalControllerPortStrategy::Random | ExternalControllerPortStrategy::AllowFallback => {
if ExternalControllerPortStrategy::AllowFallback == *strategy
&& port_scanner::local_port_available(port)
{
return Ok(port);
}
let new_port = port_scanner::request_open_port()
.ok_or_else(|| anyhow!("Can't find an open port"))?;
return Ok(new_port);
}
}
Ok(port)
}
pub fn resize_tray_image(img: &[u8], scale_factor: f64) -> Result<Vec<u8>> {
let img = ImageReader::new(Cursor::new(img))View on GitHub (pinned to f7dbce2997)
Solutions
- Find and stop the process holding the port (netstat/Get-NetTCPConnection) — usually a stale clash core.
- Switch the strategy to AllowFallback or Random so a free port is chosen automatically.
- Change the configured external-controller port to an unused one.
- Ensure previous core instances are killed before restart (check the app's core lifecycle handling).
Example fix
// before strategy: ExternalControllerPortStrategy::Fixed, // after strategy: ExternalControllerPortStrategy::AllowFallback, // fall back to a free port
Defensive patterns
Strategy: validation
Validate before calling
let port = parse_port(config.external_controller_port)?;
if strategy == ExternalControllerPortStrategy::Fixed
&& !port_scanner::local_port_available(port) {
eprintln!("port {port} busy; free it or switch to AllowFallback before starting");
} Try / catch
match get_clash_external_port(strategy, port) {
Ok(p) => p,
Err(e) if e.to_string().contains("is not available") => {
get_clash_external_port(ExternalControllerPortStrategy::Random, port)?
}
Err(e) => return Err(e),
} Prevention
- Prefer AllowFallback over Fixed unless the port must be stable
- Kill stale clash/mihomo core processes before restart
- Avoid running two app instances against the same data dir
When it happens
Trigger: Calling get_clash_external_port (via prepare_external_controller_port or patch_clash_with_rebuild) with strategy Fixed while another process — often a leftover clash/mihomo core or the app itself — is already bound to the port.
Common situations: Previous core process not fully terminated after a crash, two app instances running simultaneously, or the fixed port colliding with another service (e.g. another proxy panel).
Related errors
- port already in use
- Script mode is only available for Clash Premium
- Invalid theme color: {}
- invalid hotkey function: {s}
- cannot repair typed clash config before split_legacy_config
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/e31b82043c974eda.
Report an issue: GitHub.