shadowsocks/shadowsocks-windows · error · Exception
Port {0} already in use
Error message
Port {0} already in use What it means
Thrown by Listener.Start when CheckIfPortInUse reports that the configured localPort already has an active TCP listener in the OS. The check enumerates GetActiveTcpListeners() and looks for a matching port, so any process (including a previous Shadowsocks instance) already bound to that port will trip it. This happens before any socket is created.
Source
Thrown at shadowsocks-csharp/Controller/Service/Listener.cs:65
public Listener(List<IService> services)
{
this._services = services;
}
private bool CheckIfPortInUse(int port)
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
return ipProperties.GetActiveTcpListeners().Any(endPoint => endPoint.Port == port);
}
public void Start(Configuration config)
{
this._config = config;
this._shareOverLAN = config.shareOverLan;
if (CheckIfPortInUse(_config.localPort))
throw new Exception(I18N.GetString("Port {0} already in use", _config.localPort));
try
{
// Create a TCP/IP socket.
_tcpSocket = new Socket(config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_udpSocket = new Socket(config.isIPv6Enabled ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
IPEndPoint localEndPoint = null;
localEndPoint = _shareOverLAN
? new IPEndPoint(config.isIPv6Enabled ? IPAddress.IPv6Any : IPAddress.Any, _config.localPort)
: new IPEndPoint(config.isIPv6Enabled ? IPAddress.IPv6Loopback : IPAddress.Loopback, _config.localPort);
// Bind the socket to the local endpoint and listen for incoming connections.
_tcpSocket.Bind(localEndPoint);
_udpSocket.Bind(localEndPoint);
_tcpSocket.Listen(1024);
View on GitHub (pinned to 891d971682)
Solutions
- Find and stop the process holding the port (netstat -ano | findstr <port> on Windows, then taskkill the PID).
- Change config.localPort to a free port.
- Ensure only one instance launches at boot (disable duplicate startup entries / scheduled tasks).
- If the prior process crashed, wait briefly for the OS to release the socket, then retry.
Example fix
// before
if (CheckIfPortInUse(_config.localPort))
throw new Exception(I18N.GetString("Port {0} already in use", _config.localPort));
// after: surface which process holds the port in the message
if (CheckIfPortInUse(_config.localPort))
throw new Exception(I18N.GetString("Port {0} already in use (check netstat)", _config.localPort)); Defensive patterns
Strategy: validation
Validate before calling
// Probe the port before binding
using (var probe = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
try { probe.Bind(new IPEndPoint(IPAddress.Loopback, candidatePort)); }
catch (SocketException) { /* port not free */ }
} Type guard
bool IsPortLikelyFree(int port) =>
!IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpListeners().Any(ep => ep.Port == port); Try / catch
try { listener.Start(config); }
catch (Exception ex) when (ex.Message.Contains("already in use"))
{ /* prompt user to pick another port or kill the holder */ } Prevention
- Detect and refuse to start a second instance of the app.
- Pick a non-default port to avoid collisions with common tools.
- Surface the PID holding the port in the error to speed resolution.
When it happens
Trigger: Another Shadowsocks instance is already running on the same localPort; a different application (web server, dev tool, another proxy) occupies the port; a previous instance crashed but the OS has not yet released the listening socket (TIME_WAIT/lingering); the user changed configs and the old process is still alive.
Common situations: Starting a second copy of the client; a service set to auto-start racing with a manually launched copy; a crashed process whose socket is held by the OS; reusing a common port like 1080 that another tool also defaults to.
Related errors
AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13).
Data as JSON: /api/errors/8d70ca17133889e6.
Report an issue: GitHub.