libnyanpasu/clash-nyanpasu · error
can not select fixed: current port is not available.
Error message
can not select fixed: current port is not available.
What it means
When the patch sets `external-controller` to a fixed port, and the core is currently running, the code verifies a free external-controller port can be selected under the configured port strategy (get_clash_external_port). If selection fails, the config draft is discarded and it bails with "can not select fixed: current port is not available."
Source
Thrown at backend/tauri/src/feat.rs:307
{
Config::clash().discard();
bail!("port already in use");
}
};
// 检测 external-controller port 是否修改
if let Some(external_controller) = patch.get("external-controller") {
let external_controller = external_controller.as_str().unwrap();
let changed = external_controller != Config::clash().data().get_client_info().server;
if changed {
let (_, port) = external_controller.split_once(':').unwrap();
let port = port.parse::<u16>()?;
let strategy = Config::verge()
.latest()
.get_external_controller_port_strategy();
if core_running && get_clash_external_port(&strategy, port).is_err() {
Config::clash().discard();
bail!("can not select fixed: current port is not available.");
}
}
}
// Every desired clash patch enters the rebuild input and regenerates the
// derived config. Only port/controller/secret changes restart the core.
let restart = requires_core_restart(&patch);
let rebuilt = rebuild(restart).await?;
if restart {
handle::Handle::refresh_clash();
}
// 更新系统代理
if mixed_port.is_some() {
log_err!(sysopt::Sysopt::global().init_sysproxy());
}
if patch.get("mode").is_some() {View on GitHub (pinned to f7dbce2997)
Solutions
- Choose a different external-controller port that is currently free, and retry the patch.
- Switch the external-controller port strategy (verge config) from "fixed" to a random/range strategy so a free port is auto-selected.
- Stop the conflicting process holding the port (or restart the app to reap the stale core), then re-apply the fixed port.
Example fix
// before
patch_clash(serde_json::json!({ "external-controller": "127.0.0.1:9090" })).await?;
// after
if port_scanner::local_port_available(9090) {
patch_clash(serde_json::json!({ "external-controller": "127.0.0.1:9090" })).await?;
} else {
// leave strategy as random so get_clash_external_port picks a free port
eprintln!("9090 busy; using random external-controller port");
} Defensive patterns
Strategy: validation
Validate before calling
// before patching to a fixed external-controller port:
let port: u16 = 9090;
if !port_scanner::local_port_available(port) {
eprintln!("fixed external-controller port {} unavailable; use random strategy", port);
return;
} Try / catch
match patch_clash(patch).await {
Err(e) if e.to_string().contains("can not select fixed") => {
// fall back to a random/range port strategy and retry
},
other => other?,
} Prevention
- Prefer the random/range port strategy unless a fixed port is strictly required.
- Before pinning a fixed port, verify it is free and not used by other local services.
- Restart the app to reap stale core processes that may hold the previously selected port.
When it happens
Trigger: patch_clash with `external-controller: "127.0.0.1:<fixed-port>"` where core is running, the port strategy is "fixed", and the requested fixed port is occupied or unavailable (get_clash_external_port returns Err).
Common situations: User pins external-controller to a port already used by another app or a previous core instance; switching the port strategy to fixed while the desired port conflicts; running a second instance that already grabbed the port.
Related errors
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/5a06acb3e893ac52.
Report an issue: GitHub.