{"record":{"id":"2c302128708be617","repo":"libnyanpasu/clash-nyanpasu","slug":"port-already-in-use","errorCode":null,"errorMessage":"port already in use","messagePattern":"port already in use","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/feat.rs","lineNumber":291,"sourceCode":"\n    let run = move || async move {\n        let mixed_port = patch.get(\"mixed-port\");\n        let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);\n        if let Some(mixed_port) = mixed_port\n            && !enable_random_port\n        {\n            let changed = mixed_port\n                != Config::verge()\n                    .latest()\n                    .verge_mixed_port\n                    .unwrap_or(Config::clash().data().get_mixed_port());\n            // 检查端口占用\n            if changed\n                && let Some(port) = mixed_port.as_u64()\n                && !port_scanner::local_port_available(port as u16)\n            {\n                Config::clash().discard();\n                bail!(\"port already in use\");\n            }\n        };\n\n        // 检测 external-controller port 是否修改\n        if let Some(external_controller) = patch.get(\"external-controller\") {\n            let external_controller = external_controller.as_str().unwrap();\n            let changed = external_controller != Config::clash().data().get_client_info().server;\n            if changed {\n                let (_, port) = external_controller.split_once(':').unwrap();\n                let port = port.parse::<u16>()?;\n                let strategy = Config::verge()\n                    .latest()\n                    .get_external_controller_port_strategy();\n                if core_running && get_clash_external_port(&strategy, port).is_err() {\n                    Config::clash().discard();\n                    bail!(\"can not select fixed: current port is not available.\");\n                }\n            }","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/feat.rs#L273-L309","documentation":"During a clash config patch, if the mixed-port value is being changed, the code first checks whether the new port is free on localhost using port_scanner::local_port_available. If the port is occupied, it discards the config draft and bails with \"port already in use\" so the core is never restarted onto a port that cannot bind.","triggerScenarios":"Calling patch_clash (via patch_clash_with_rebuild) with a patch containing a `mixed-port` that differs from the current value and is already bound by another process (another proxy, mihomo instance, dev server, or a stale core process).","commonSituations":"Users setting mixed-port to a value already used by another local service; two copies of the app (or clash-verge/mihomo) running simultaneously; a zombie core process still holding the old/new port; configuring a port below 1024 on systems with restrictions.","solutions":["Pick a different mixed-port that is free (check with `netstat -ano | findstr <port>` / `ss -ltnp | grep <port>`).","Kill the process occupying the port (stale clash/mihomo core or another proxy app) and retry the patch.","Fully restart the app so lingering core processes are cleaned up, then apply the port change again."],"exampleFix":"// before\nlet patch = serde_json::json!({ \"mixed-port\": 7890 });\npatch_clash(patch).await?;\n// after\nif port_scanner::local_port_available(7890) {\n    patch_clash(serde_json::json!({ \"mixed-port\": 7890 })).await?;\n} else {\n    eprintln!(\"port 7890 is taken; choose another\");\n}","handlingStrategy":"validation","validationCode":"if let Some(port) = patch.get(\"mixed-port\").and_then(|v| v.as_u64()) {\n    if !port_scanner::local_port_available(port as u16) {\n        eprintln!(\"port {} is already in use; pick another\", port);\n        return;\n    }\n}","typeGuard":null,"tryCatchPattern":"match patch_clash(patch).await {\n    Err(e) if e.to_string().contains(\"port already in use\") => {\n        // prompt user for a different mixed-port\n    },\n    other => other?,\n}","preventionTips":["Check port availability before submitting config changes.","Avoid well-known ports commonly used by other dev tools (3000, 8080, 9090).","Ensure only one app/core instance runs at a time; clean up stale core processes after crashes."],"tags":["port","network","configuration"],"backgroundTag":"address-already-in-use","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}