netchx/netch · error · MessageException

The port is used by .

Error message

The {0} port is used by {1}.

What it means

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.

Solutions

  1. Read the PID and path from the message, then close that application yourself.
  2. Pick a different port in Netch settings to avoid the conflict.
  3. If the named process is something you don't recognize, investigate before killing.
  4. Re-run Start after the third-party process has released the port.
Defensive patterns

Strategy: validation

Validate before calling

// Detect a third-party holder before TryReleaseTcpPort throws.
var holders = PortHelper.GetProcessByUsedTcpPort(port)
    .Where(p => p.MainModule?.FileName is { } f && !f.StartsWith(Global.NetchDir));
if (holders.Any())
    throw new MessageException($"Port {port} is held by a non-Netch process: {string.Join(",", holders.Select(p => p.ProcessName))}");

Try / catch

try { MainController.TryReleaseTcpPort(port, portName); }
catch (MessageException ex) when (ex.Message.Contains("port is used by"))
{
    // message names the PID + exe; prompt user to close it or change port
    PromptCloseOrChangePort(ex.Message);
}

Prevention

When it happens

Trigger: 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).

Common situations: Another proxy client occupies the Socks5 port; a leftover system service binds the port; user manually started a server on that port.

Related errors


AI-assisted analysis of netchx/netch@9d99eb1c5a (2026-08-13). Data as JSON: /api/errors/69ae648eb00d6a8c. Report an issue: GitHub.

Appendix: source

Thrown at Netch/Controllers/MainController.cs:165

        }
    }

    public static void TryReleaseTcpPort(ushort port, string portName)
    {
        foreach (var p in PortHelper.GetProcessByUsedTcpPort(port))
        {
            var fileName = p.MainModule?.FileName;
            if (fileName == null)
                continue;

            if (fileName.StartsWith(Global.NetchDir))
            {
                p.Kill();
                p.WaitForExit();
            }
            else
            {
                throw new MessageException(i18N.TranslateFormat("The {0} port is used by {1}.", $"{portName} ({port})", $"({p.Id}){fileName}"));
            }
        }

        PortCheck(port, portName, PortType.TCP);
    }

    public static Task<NatTypeTestResult> DiscoveryNatTypeAsync(CancellationToken ctx = default)
    {
        Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
        return Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx);
    }

    public static Task<int?> HttpConnectAsync(CancellationToken ctx = default)
    {
        Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
        try
        {
            return Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);

View on GitHub (pinned to 9d99eb1c5a)