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

  1. Choose a different external-controller port that is currently free, and retry the patch.
  2. Switch the external-controller port strategy (verge config) from "fixed" to a random/range strategy so a free port is auto-selected.
  3. 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

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.