{"record":{"id":"69ae648eb00d6a8c","repo":"netchx/netch","slug":"the-0-port-is-used-by-1","errorCode":null,"errorMessage":"The {0} port is used by {1}.","messagePattern":"The (.+?) port is used by (.+?)\\.","errorType":"exception","errorClass":"MessageException","httpStatus":null,"severity":"error","filePath":"Netch/Controllers/MainController.cs","lineNumber":165,"sourceCode":"        }\n    }\n\n    public static void TryReleaseTcpPort(ushort port, string portName)\n    {\n        foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))\n        {\n            var fileName = p.MainModule?.FileName;\n            if (fileName == null)\n                continue;\n\n            if (fileName.StartsWith(Global.NetchDir))\n            {\n                p.Kill();\n                p.WaitForExit();\n            }\n            else\n            {\n                throw new MessageException(i18N.TranslateFormat(\"The {0} port is used by {1}.\", $\"{portName} ({port})\", $\"({p.Id}){fileName}\"));\n            }\n        }\n\n        PortCheck(port, portName, PortType.TCP);\n    }\n\n    public static Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)\n    {\n        Debug.Assert(Socks5Server != null, nameof(Socks5Server) + \" != null\");\n        return Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);\n    }\n\n    public static Task<int?> HttpConnectAsync(CancellationToken ctx = default)\n    {\n        Debug.Assert(Socks5Server != null, nameof(Socks5Server) + \" != null\");\n        try\n        {\n            return Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/netchx/netch/blob/9d99eb1c5a2acbf2a34f2600f94242601019a300/Netch/Controllers/MainController.cs#L147-L183","documentation":"Thrown by MainController.TryReleaseTcpPort when a process holding the TCP port was found via PortHelper.GetProcessByUsedTcpPort, but its MainModule.FileName does NOT start with Global.NetchDir — i.e. a third-party process owns the port and Netch refuses to kill it. The message names the PID and executable path.","triggerScenarios":"Calling TryReleaseTcpPort for a port used by a browser, another proxy tool, IIS, a dev server, or any non-Netch process; the owning process has already exited but a stale entry remained (then fileName null -> skipped).","commonSituations":"Another proxy client occupies the Socks5 port; a leftover system service binds the port; user manually started a server on that port.","solutions":["Read the PID and path from the message, then close that application yourself.","Pick a different port in Netch settings to avoid the conflict.","If the named process is something you don't recognize, investigate before killing.","Re-run Start after the third-party process has released the port."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Detect a third-party holder before TryReleaseTcpPort throws.\nvar holders = PortHelper.GetProcessByUsedTcpPort(port)\n    .Where(p => p.MainModule?.FileName is { } f && !f.StartsWith(Global.NetchDir));\nif (holders.Any())\n    throw new MessageException($\"Port {port} is held by a non-Netch process: {string.Join(\",\", holders.Select(p => p.ProcessName))}\");","typeGuard":null,"tryCatchPattern":"try { MainController.TryReleaseTcpPort(port, portName); }\ncatch (MessageException ex) when (ex.Message.Contains(\"port is used by\"))\n{\n    // message names the PID + exe; prompt user to close it or change port\n    PromptCloseOrChangePort(ex.Message);\n}","preventionTips":["Default to a port no other app uses.","Close competing proxy clients (Clash, v2rayN) before starting Netch.","Don't pin Netch to a port a dev server or browser uses.","Document the PID+path from the message so users know exactly what to close."],"tags":["port","process","network","validation"],"backgroundTag":null,"analyzedSha":"9d99eb1c5a2acbf2a34f2600f94242601019a300","analyzedAt":"2026-08-13T14:12:19.105Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}