Skip to content

Display useful suggestions in error message on windows when port reserved? (bind EACCES) #2894

@ariccio

Description

@ariccio

Is your feature request related to a problem? Please describe.
A problem I encounter all the time on windows is that Hyper-V (or someone else) will reserve a port like port 3000. It's not in use, it's reserved. If I try to start up rails with the default port, then everything will crash when puma fails to create a TCPServer on that port. It's not obvious from the documentation that TCPServer.new can raise (though it does), so puma does not handle this.

I'm used to diagnosing this, you need to check the reserved ports with netsh interface ipv4 show excludedportrange protocol=tcp, but this is quite surprising if you have no idea what's going on. If you check the ports in use, you will see that port is not in use! The only fix is to reboot, something you may end up doing in the meantime, and likely you won't know why it worked.

Because puma does not handle this, rails (or whatever app you're using) simply crashes with a stacktrace, and the message C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/puma-5.6.4/lib/puma/binder.rb:341:in initialize': Permission denied - bind(2) for "::1" port 3000 (Errno::EACCES)`.

Describe the solution you'd like
One useful option might be to detect when (on Windows) the exception is EACCES instead of EADDRINUSE, and dump a useful error to the screen before reraising. The message could be something like:

bind(2) for "::1" port 3000 failed with EACCES. On Windows, the port might be reserved even if it's not in use by a process. To check if it's reserved, run this command, and check if the port in question is in the listed ranges:
`netsh interface ipv4 show excludedportrange protocol=tcp`

Sometimes, this is the result of Hyper-V reserving ports. In that case, the solution is to reboot the machine until it has allocated a different port.

If in an interactive session, this wouldn't change any behavior, since it would still run through the current exception handling. In any other context, it could cause issues, so I do not expect this to be the solution you adopt :) You could check to see if puma is running in an interactive context too.

Describe alternatives you've considered
One option is puma could run the command in a subshell and parse the results to see if it's in the range before providing a message. That sounds like extra complexity.

Additional context
I suspect many other kernel mode things could allocate/reserve the port, but Hyper-V is certainly the thing that I most commonly encounter. Those would still probably show up in the excludedportrange, but I have no clue if they would also choose a random set of ports on each boot. I don't know why Hyper-V does this specifically... it could be an anti-anti-debugging/anti-sandbox-evasion feature?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions