Skip to content

[Bug]: Socket resource leak in _check_port_available when port is in use #91

@ze-mu-zhou

Description

@ze-mu-zhou

Bug Description

AGFSManager._check_port_available() (openviking/agfs_manager.py lines 113–123) creates a socket but only closes it on the success path. When sock.bind() raises OSError (port already in use), the code raises RuntimeError without ever closing the socket, leaking a file descriptor.

def _check_port_available(self) -> None:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.bind(("localhost", self.port))
        sock.close()          # Only reached on success
    except OSError as e:
        raise RuntimeError(   # sock is never closed here
            f"AGFS port {self.port} is already in use..."
        ) from e

Steps to Reproduce

import socket
from openviking.agfs_manager import AGFSManager

# Occupy a port
blocker = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
blocker.bind(("localhost", 19998))
blocker.listen(1)

# Call _check_port_available on the occupied port
mgr = AGFSManager.__new__(AGFSManager)
mgr.port = 19998

try:
    mgr._check_port_available()
except RuntimeError:
    pass  # Socket fd leaked here

blocker.close()

Expected Behavior

The socket should be closed on both success and failure paths, e.g. using finally: sock.close().

Actual Behavior

Python emits a ResourceWarning confirming the socket was never closed:

Exception ignored in: <socket.socket fd=664, family=2, type=1, proto=0>
ResourceWarning: unclosed <socket.socket fd=664, family=2, type=1, proto=0>

Each failed call leaks one file descriptor.

Minimal Reproducible Example

import socket
import warnings

warnings.simplefilter("error", ResourceWarning)

from openviking.agfs_manager import AGFSManager

blocker = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
blocker.bind(("localhost", 19998))
blocker.listen(1)

mgr = AGFSManager.__new__(AGFSManager)
mgr.port = 19998

try:
    mgr._check_port_available()
except RuntimeError:
    pass

import gc
gc.collect()
# ResourceWarning: unclosed <socket.socket fd=664, ...>

blocker.close()

Error Logs

Exception ignored in: <socket.socket fd=664, family=2, type=1, proto=0>
ResourceWarning: unclosed <socket.socket fd=664, family=2, type=1, proto=0>

OpenViking Version

0.1.10 (main branch, 2026-02-07)

Python Version

3.13.7

Operating System

Windows

Model Backend

Other

Additional Context

Fix is straightforward — move sock.close() into a finally block:

def _check_port_available(self) -> None:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.bind(("localhost", self.port))
    except OSError as e:
        raise RuntimeError(
            f"AGFS port {self.port} is already in use..."
        ) from e
    finally:
        sock.close()

In retry scenarios or test suites where _check_port_available is called repeatedly with an occupied port, this leak can accumulate and eventually exhaust file descriptors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions