{"record":{"id":"cbad9de78421d7f1","repo":"libnyanpasu/clash-nyanpasu","slug":"can-t-find-an-open-port","errorCode":null,"errorMessage":"Can't find an open port","messagePattern":"Can't find an open port","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"backend/tauri/src/utils/help.rs","lineNumber":174,"sourceCode":"\npub fn get_clash_external_port(\n    strategy: &ExternalControllerPortStrategy,\n    port: u16,\n) -> anyhow::Result<u16> {\n    match strategy {\n        ExternalControllerPortStrategy::Fixed => {\n            if !port_scanner::local_port_available(port) {\n                bail!(\"Port {} is not available\", port);\n            }\n        }\n        ExternalControllerPortStrategy::Random | ExternalControllerPortStrategy::AllowFallback => {\n            if ExternalControllerPortStrategy::AllowFallback == *strategy\n                && port_scanner::local_port_available(port)\n            {\n                return Ok(port);\n            }\n            let new_port = port_scanner::request_open_port()\n                .ok_or_else(|| anyhow!(\"Can't find an open port\"))?;\n            return Ok(new_port);\n        }\n    }\n    Ok(port)\n}\n\npub fn resize_tray_image(img: &[u8], scale_factor: f64) -> Result<Vec<u8>> {\n    let img = ImageReader::new(Cursor::new(img))\n        .with_guessed_format()?\n        .decode()?;\n    let width = img.width();\n    let height = img.height();\n    let src_pixels = img.into_rgba8().into_raw();\n    let src_image = ImageRef::new(width, height, &src_pixels, PixelType::U8x4)\n        .context(\"failed to parse image\")?;\n\n    // Create container for data of destination image\n    let size = (32_f64 * scale_factor).round() as u32; // 32px is the base tray size as the dpi is 96","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/utils/help.rs#L156-L192","documentation":"get_clash_external_port resolves the external controller port. With the AllowFallback strategy, if the configured port is occupied it calls port_scanner::request_open_port() for any free port; if the scanner finds none, this error is thrown. It means no bindable local port could be found at all.","triggerScenarios":"request_open_port() finds every candidate port bound - heavily loaded machines, containers with exhausted ephemeral port ranges, or sandboxes where bind() is denied for all ports.","commonSituations":"Docker/CI environments with net.ipv4.ip_local_port_range exhausted, huge TIME_WAIT socket counts, or firewall/security software blocking port binds.","solutions":["Free ports: kill stale listeners or widen the ephemeral range (sysctl net.ipv4.ip_local_port_range).","Check firewall/security software that may block binds on all ports.","Restart the host/network stack to clear TIME_WAIT sockets.","Pin a known-free port or change the strategy so no fallback scan is needed."],"exampleFix":"# before\nsysctl net.ipv4.ip_local_port_range  # 32768 60999, exhausted\n# after\nsudo sysctl -w net.ipv4.ip_local_port_range=\"1024 65535\"","handlingStrategy":"retry","validationCode":"// check a bindable port exists before launch (node)\nconst net = require('net');\nconst s = net.createServer(); s.listen(0, () => { console.log('bindable'); s.close(); });","typeGuard":null,"tryCatchPattern":"try {\n  await startCore();\n} catch (e) {\n  if (String(e).includes(\"Can't find an open port\")) {\n    retryWithBackoff(startCore, 3); // transient port exhaustion\n  } else throw e;\n}","preventionTips":["Monitor ephemeral port exhaustion in long-running hosts","Raise net.ipv4.ip_local_port_range on servers/containers","Avoid running hundreds of listeners in the same netns"],"tags":["ports","network","port-scan"],"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-17T15:17:12.973Z"}