netchx/netch · error · MessageException

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

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.

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)

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.