BeyondDimension/SteamTools · error · ApplicationException
TCP port {httpProxyPort} is already occupied by other proces
Error message
TCP port {httpProxyPort} is already occupied by other processes. What it means
Thrown during Kestrel server startup when the configured HTTP proxy port is already bound by another process. ListenHttpProxy resolves the configured HttpProxyPort and probes it with IsAvailableTcp before calling options.Listen; if the probe fails the listener is never created and the app fails fast rather than hitting an OS bind error later.
Source
Thrown at src/BD.WTTS.Client.Plugins.Accelerator.ReverseProxy/Extensions/KestrelServerOptionsExtensions.cs:32
{
options.Limits.MaxRequestBodySize = null;
options.Limits.MinResponseDataRate = null;
options.Limits.MinRequestBodyDataRate = null;
}
/// <summary>
/// 监听 Http 代理
/// </summary>
/// <param name="options"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ListenHttpProxy(this KestrelServerOptions options)
{
var reverseProxyConfig = options.ApplicationServices.GetRequiredService<IReverseProxyConfig>();
var httpProxyPort = reverseProxyConfig.HttpProxyPort;
if (!IReverseProxyConfig.IsAvailableTcp(httpProxyPort))
{
throw new ApplicationException(
$"TCP port {httpProxyPort} is already occupied by other processes.");
}
options.Listen(IReverseProxyService.Constants.Instance.ProxyIp, httpProxyPort, listen =>
{
listen.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
var proxyMiddleware = options.ApplicationServices.GetRequiredService<HttpProxyMiddleware>();
var tunnelMiddleware = options.ApplicationServices.GetRequiredService<TunnelMiddleware>();
listen.UseFlowAnalyze();
listen.Use(next => context => proxyMiddleware.InvokeAsync(next, context));
listen.UseTls();
listen.Use(next => context => tunnelMiddleware.InvokeAsync(next, context));
});
options.GetLogger().LogInformation(
"Listened http://{ProxyIp}:{httpProxyPort}, HTTP proxy service startup completed.",
IReverseProxyService.Constants.Instance.ProxyIp, httpProxyPort);View on GitHub (pinned to c16ffa08e0)
Solutions
- Free the port: find and stop the process holding it (e.g. netstat/Get-NetTCPConnection + taskkill) then restart.
- Change the configured HttpProxyPort to a free port and restart the service.
- Ensure no second instance of the application is running before startup.
- If caused by TIME_WAIT, wait briefly or enable SO_REUSEADDR on the conflicting listener.
Example fix
// before: fixed port collision
var httpProxyPort = reverseProxyConfig.HttpProxyPort; // e.g. 8888, already in use
// after: fall back to a free port when the configured one is busy
var httpProxyPort = reverseProxyConfig.HttpProxyPort;
if (!IReverseProxyConfig.IsAvailableTcp(httpProxyPort))
httpProxyPort = IReverseProxyConfig.GetAvailableTcpPort(httpProxyPort + 1); Defensive patterns
Strategy: validation
Validate before calling
// Probe the port BEFORE configuring Kestrel and pick an alternative if busy.
int ResolveProxyPort(IReverseProxyConfig cfg)
{
var port = cfg.HttpProxyPort;
if (!IReverseProxyConfig.IsAvailableTcp(port))
{
Log.Warning($"Configured proxy port {port} busy; searching for a free one.");
port = IReverseProxyConfig.GetAvailableTcpPort(cfg.HttpProxyPort + 1);
}
return port;
} Try / catch
try { options.ListenHttpProxy(); }
catch (ApplicationException ex) when (ex.Message.Contains("already occupied"))
{
// Surface to the user with the port number and offer to change it / kill the holder.
Log.Error(TAG, ex, "Proxy port conflict during startup.");
throw;
} Prevention
- Pin the proxy port to a rarely-used high port and document it; ensure no other tool uses it.
- On shutdown, explicitly stop the Kestrel listener so the socket is released (avoid TIME_WAIT).
- Detect a stale previous instance at startup (pid file / named mutex) and refuse/replace it before binding.
- Add a startup health check that logs which process holds the configured port.
When it happens
Trigger: Calling ListenHttpProxy (during reverse-proxy startup) when another process — a previous app instance that did not release the socket, a different proxy, or a system service — is already listening on the configured HttpProxyPort.
Common situations: App was killed and the socket is still in TIME_WAIT or held by a zombie process; another accelerator/proxy (Clash, v2ray, Fiddler) occupies the same port; the port was changed in config to one already in use; developer is running two instances.
Related errors
- Failed to get available ports. There are no available ports.
- 5
- Could not install certificate as it is null or empty.
- Could not find any IP that can be successfully connected.
- Unable to connect to {host}
AI-assisted analysis of BeyondDimension/SteamTools@c16ffa08e0 (2026-08-13).
Data as JSON: /api/errors/9f67b7dc220e040e.
Report an issue: GitHub.