diff --git a/lightly_studio/src/lightly_studio/api/server.py b/lightly_studio/src/lightly_studio/api/server.py index 1dd7c4d00..81f868361 100644 --- a/lightly_studio/src/lightly_studio/api/server.py +++ b/lightly_studio/src/lightly_studio/api/server.py @@ -73,10 +73,12 @@ def _is_port_available(host: str, port: int) -> bool: # Fallback for hostnames like 'localhost' families = [socket.AF_INET, socket.AF_INET6] + # The port is available if we can bind to at least one address family. for family in families: with socket.socket(family, socket.SOCK_STREAM) as s: try: s.bind((host, port)) + return True except OSError: - return False - return True + continue + return False diff --git a/lightly_studio/tests/api/test_server.py b/lightly_studio/tests/api/test_server.py index 35900f5d1..0b7cfa54d 100644 --- a/lightly_studio/tests/api/test_server.py +++ b/lightly_studio/tests/api/test_server.py @@ -81,3 +81,19 @@ def test__get_available_port__preferred_port_in_use() -> None: server = Server(host, port) s.close() assert server.port != port + + +def test__get_available_port__localhost_with_ipv6_failure() -> None: + """Test that port is available even if IPv6 binding fails for localhost. + + This tests the fix for the bug where _is_port_available returned False + when checking 'localhost' because IPv6 binding failed, even though IPv4 + binding succeeded. The port should be considered available if at least + one address family can bind successfully. + """ + host = "localhost" + port = 8002 + + # Verify that the port is available. + server = Server(host=host, port=port) + assert server.port == port