Skip to content

fix: require python-daemon>=2.2.4 so luigid --background works on Python 3.13 - #3431

Open
DRACULA1729 wants to merge 2 commits into
spotify:masterfrom
DRACULA1729:fix/python-daemon-min-version-3407
Open

fix: require python-daemon>=2.2.4 so luigid --background works on Python 3.13#3431
DRACULA1729 wants to merge 2 commits into
spotify:masterfrom
DRACULA1729:fix/python-daemon-min-version-3407

Conversation

@DRACULA1729

@DRACULA1729 DRACULA1729 commented Jun 14, 2026

Copy link
Copy Markdown

Description

luigid --background crashes on Python 3.13 with OSError: [Errno 88] Socket operation on non-socket. The crash is in the python-daemon dependency, not in luigi.

When luigi builds the DaemonContext in luigi/process.py it doesn't pass detach_process, so python-daemon decides whether to detach by checking if stdin is a socket (i.e. whether it was started by inetd / a superserver). That check calls socket.fromfd(fd, AF_INET, SOCK_RAW) on fd 0. Python 3.13 validates the fd inside the socket() constructor and raises ENOTSOCK for a non-socket, and old python-daemon left that fromfd call outside its try/except, so the error escapes. That's why foreground luigid and Python 3.12 are both fine: neither hits this path.

python-daemon fixed this in 2.2.4 ("Create the socket and catch 'non-socket' errors") by moving fromfd inside the try/except that handles ENOTSOCK. luigi declared no minimum python-daemon version on non-Windows, so a pre-2.2.4 release could satisfy the install and still crash. uv.lock was even resolving python-daemon to 2.1.2 on every platform, because the win32 <2.2.0 cap pulled the universal resolution down while non-Windows had no floor.

This adds the lower bound and regenerates the lockfile:

- "python-daemon; sys_platform != 'win32'",
+ "python-daemon>=2.2.4; sys_platform != 'win32'",

After the change the lock resolves python-daemon 3.1.2 on non-Windows (the patched line) and keeps 2.1.2 on win32 under its existing <2.2.0 cap. 2.2.4 is the exact release that fixed the bug, so it's the minimal bound.

Motivation and Context

Fixes #3407. luigid --background is broken on Python 3.13, which luigi supports (requires-python = ">=3.10, <3.14"). Foreground luigid still works, so this only affects daemon mode.

Have you tested this? If so, how?

I reproduced the crash and verified the fix on a clean Python 3.13.13 environment.

Before, with python-daemon 2.1.2 (the version the old lock pinned), luigid --background --logdir ./logs exits 1 with the same traceback as #3407:

File ".../luigi/process.py", line 94, in daemonize
    ctx = daemon.DaemonContext(...)
File ".../daemon/daemon.py", line 778, in is_process_started_by_superserver
    if is_socket(stdin_fd):
File ".../daemon/daemon.py", line 743, in is_socket
    file_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_RAW)
OSError: [Errno 88] Socket operation on non-socket

After, with python-daemon 3.1.2 (what >=2.2.4 resolves to), the same command exits 0. The daemon forks into the background, writes its pidfile, the scheduler logs "Scheduler starting up", and the HTTP API answers 200 on :8082.

CI is green and uv sync --locked passes with the regenerated lockfile.

…hon 3.13

Running `luigid --background` on Python 3.13 crashes with "OSError:
[Errno 88] Socket operation on non-socket". The error comes from
python-daemon, not luigi: while building the DaemonContext it auto-detects
whether to detach by checking if stdin is a socket, which calls
socket.fromfd on fd 0. On 3.13 socket.fromfd validates the fd in the
socket() constructor and raises ENOTSOCK for a non-socket, and in old
python-daemon that call sits outside the try/except so the error escapes.

python-daemon fixed this in 2.2.4 by moving the fromfd call inside the
try/except that catches ENOTSOCK. luigi declared no minimum version on
non-Windows, so a pre-2.2.4 release could satisfy the install and still
crash. Add a >=2.2.4 lower bound, which is the exact release that fixed it.

Fixes spotify#3407
@DRACULA1729
DRACULA1729 requested review from a team and dlstadther as code owners June 14, 2026 19:05
CI runs `uv sync --locked`, which requires uv.lock to match pyproject.toml.
Regenerating the lock resolves python-daemon to 3.1.2 on non-Windows (the
fixed line) while win32 stays on 2.1.2 under its <2.2.0 cap.

Notably the lock previously pinned python-daemon 2.1.2 for all platforms:
the win32 <2.2.0 cap dragged the universal resolution down because
non-Windows had no floor. That 2.1.2 is exactly the pre-2.2.4 version that
crashes under spotify#3407, so this also fixes the resolution the project itself
ships.
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.

OSError: [Errno 88] Socket operation on non-socket when running luigid --background on Python 3.13

2 participants