Skip to content

Conversation

@eternal-f1ame
Copy link

@eternal-f1ame eternal-f1ame commented Nov 14, 2025

Fix port availability check for dual-stack localhost binding

Description

This PR fixes a bug in _is_port_available() where the server would fail to start with RuntimeError: Could not find an available port even when ports were actually available.

Root Cause

The bug occurred when checking port availability on localhost on systems with dual-stack networking (IPv4/IPv6):

  1. The function attempted to bind to both AF_INET (IPv4) and AF_INET6 (IPv6) address families
  2. On systems where IPv6 is not fully configured for localhost, the IPv6 bind would fail
  3. The function used AND logic: it returned False if any address family failed to bind
  4. This caused the function to report ports as unavailable even when IPv4 binding succeeded

Solution

Changed the logic to use OR semantics:

  • The port is now considered available if at least one address family can successfully bind
  • Added early return on first successful bind attempt
  • Port is only unavailable if all address families fail to bind

Changes Made

lightly_studio/src/lightly_studio/api/server.py:

  • Modified _is_port_available() function to return True on first successful bind
  • Added comment explaining the OR logic
  • Changed from "all must succeed" to "any succeeds" pattern

lightly_studio/tests/api/test_server.py:

  • Added test case test__get_available_port__localhost_with_ipv6_failure()
  • Validates that port availability check succeeds even when IPv6 binding might fail

Testing

Manual Testing

import lightly_studio as ls

# Indexes the dataset, creates embeddings and stores everything in the database. Here we only load images.
dataset = ls.Dataset.create()
dataset.add_samples_from_path(path="dataset_examples/coco_subset_128_images/images")

# Start the UI server on localhost:8001.
# Use env variables LIGHTLY_STUDIO_HOST and LIGHTLY_STUDIO_PORT to customize it.
ls.start_gui()

Before fix: RuntimeError: Could not find an available port
After fix: Server starts successfully on port 8001

Unit Tests

cd lightly_studio
make test

All existing tests pass, plus new test case validates the fix.

Impact

  • Low risk: Changes only affect port availability checking logic
  • Backwards compatible: No API or behavior changes for end users
  • Improves reliability: Server now starts correctly on systems with partial IPv6 support

Related Issues

Fixes the issue where users encountered:

RuntimeError: Could not find an available port.

Checklist

  • Code follows project coding guidelines
  • Added unit test for the bug fix
  • All existing tests pass
  • Manual testing confirms fix works
  • Commit message follows conventional format

Fix bug in _is_port_available() where the function would incorrectly
return False when checking 'localhost' because IPv6 binding failed,
even though IPv4 binding succeeded.

The issue occurred because the function tested both AF_INET and AF_INET6
address families for hostnames like 'localhost', and returned False if
ANY family failed to bind, even if at least one succeeded.

Changes:
- Modified _is_port_available() to return True if ANY address family
  can successfully bind to the port (OR logic instead of AND logic)
- Added early return on first successful bind attempt
- Added test case test__get_available_port__localhost_with_ipv6_failure
  to verify the fix

This resolves the 'RuntimeError: Could not find an available port' error
that occurred on systems where IPv6 is not fully configured for localhost.
@michal-lightly
Copy link
Contributor

Hi @eternal-f1ame, thanks for submitting the PR, we are going to have a look in the next few days.

@mihnea-necsulescu
Copy link
Contributor

Hey @eternal-f1ame, thanks again for bringing this up and for contributing the PR! We analyzed the underlying issue and concluded that we will need a different approach to address possible corner cases as well. We will link the solving PR here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants