Repository navigation
Windows: pip self-update through loopx.exe can fail with WinError 32 and leave the CLI unimportable #6804
Description
Problem and user impact
On native Windows, a pip-owned installation can advertise loopx update apply as supported, then fail while upgrading the executable that is running that request. In a disposable environment, the failed uninstall left the CLI package unimportable: import loopx raised ModuleNotFoundError. The JSON response returned nonzero with changes_applied=false, although files had already been removed or renamed by pip. No live project or user installation was used for this experiment.
Reproduction
Environment: Windows 10, PowerShell 7, CPython 3.12.10 and pip 26.2.1. Install the published loopx==1.4.0 wheel into a new pip-owned virtual environment and put its Scripts directory on PATH. Use a disposable HOME/profile and explicit synthetic registry/runtime routes.
- Create a synthetic claimed Todo and acquire its lease; exit that PowerShell session.
- Optionally constrain the test's pip resolution to
loopx==1.4.2so the comparison has an immutable target. - In a fresh PowerShell process, run the environment's console executable:
loopx.exe --format json update plan. It reports ownerpython_package_manager, driverpython_pip, and apply supported. - Run that same console executable with
--format json update apply --timeout-seconds 90.
Observed: the child pip downloads 1.4.2, begins uninstalling 1.4.0, then fails with OSError: [WinError 32] naming Scripts/loopx.exe. install_returncode=1; the later authority/skills/doctor steps are skipped. After the request exits, the same environment's Python cannot import loopx. This is more than an unsuccessful no-op.
Controlled counterfactual and recovery
After the failed console process exited, explicitly reinstalling loopx==1.4.0 through that environment's Python restored the damaged test installation. With the same project, routes, pip owner, fixed target and environment, run:
# Use the owning environment's python executable.
python -m loopx.entrypoint --format json update apply --timeout-seconds 90That module-entry invocation completed the package install, authority upgrade, workflow skills, slash commands, doctor and enabled-extension doctor with return code 0 for every step. A fresh process verified installed version 1.4.2. The original synthetic Todo and lease survived; artifact validation refusal, successful completion, fresh-shell receipt readback and unchanged completion replay all passed.
If an installation is already damaged, the module command alone cannot recover a missing module. Restore the chosen package explicitly with the owning interpreter's python -m pip install loopx==<chosen-version> first, after the failed console process has exited. Check data-format compatibility before selecting an older version. This report does not recommend downgrading live data or changing installation owners.
Owning boundary and expected result
The existing Python package-manager adapter in loopx/self_update.py::_execute_python_distribution_update invokes pip while the outer console launcher is still alive. The entry-mode comparison and locked executable identify that boundary; this is separate from unsupported native archive updates. The same source file remains unchanged at main 860e42d4b63b45c4798ee7f08622a27c146a2610 (Git blob 053c862bb78599f9be0d73b6036d64a1360a8067). That is source inspection, not a full execution of current main.
The Windows console path should avoid starting a destructive uninstall it cannot complete. A bounded solution may refuse before mutation and supply the exact owning-interpreter module invocation; an automatic handoff would separately need truthful lifecycle/result delivery. Failed pip installation must not be presented as evidence that no installation files changed.
Related #6789 composes CLI/macOS App upgrades and retains the package-manager owner; this report records the demonstrated Windows console-lock failure rather than duplicating that program. No implementation, scoring change, model run, release or system upgrade is proposed here.
Acceptance: on native Windows, prove refusal or successful replacement through the real console entry; preserve an installed/importable CLI, the original synthetic task and lease, and successful module-entry recovery. Keep pip failure and incomplete-update evidence visible. POSIX/package-owner behavior should remain unchanged.
Activity