From 9ef02dd06f54a96cc2b95e203fe8eb5706365e3b Mon Sep 17 00:00:00 2001 From: BigBodyCobain Date: Fri, 22 May 2026 18:50:27 -0600 Subject: [PATCH] Fix #296: reject backend venvs missing uvicorn before launch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported by @f3n3k on Windows native install path. Symptom: C:\001\backend\venv\Scripts\python.exe: No module named uvicorn [backend] exited with 1 ShadowBroker has stopped. Exit code: 1 Root cause ---------- The Windows Start.bat flow chains: Start.bat └─ scripts\run-windows-runtime.ps1 └─ frontend\scripts\dev-all.cjs └─ start-backend.js └─ backend\venv\Scripts\python.exe -m uvicorn main:app `start-backend.js` decided whether an existing `backend\venv` was usable by calling `canRun(candidate, ["-V"])`. That only checks whether Python itself can run — it does NOT check whether the backend's actual runtime dependencies are installed. When the venv exists but `pip install` never finished (partial install, failed network, interrupted bootstrap, etc.), the launcher happily accepted that broken venv, then died with the exact error f3n3k reported. Fix --- New `canRunBackendPython()` helper that requires BOTH: python -V # Python is runnable python -c "import fastapi, uvicorn" # backend deps are installed Used in two call sites: * `ensureBackendVenv()` — when iterating candidate venvs on first launch, reject any venv whose Python can't import the backend's real entry-point deps. The launcher then falls through to its existing rebuild path (`rebuildBackendVenv`) which reinstalls deps before declaring the venv healthy. * `rebuildBackendVenv()` — after a rebuild attempt, verify the deps are present before returning the new interpreter path. Catches silent partial rebuilds. The check is the import that uvicorn itself would do at startup, so a green return here genuinely means "uvicorn will start". Cost is one extra `python -c` per venv candidate on launcher startup — milliseconds. Verified locally with `node --check start-backend.js`. Credit: @f3n3k for the original report. --- start-backend.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/start-backend.js b/start-backend.js index 4650e38..212f5cf 100644 --- a/start-backend.js +++ b/start-backend.js @@ -76,6 +76,13 @@ function canRun(command, args) { return !result.error && result.status === 0; } +function canRunBackendPython(pythonBin) { + return ( + canRun(pythonBin, ["-V"]) && + canRun(pythonBin, ["-c", "import fastapi, uvicorn"]) + ); +} + function findBasePython() { const candidates = isWindows ? [ @@ -135,12 +142,12 @@ function rebuildBackendVenv(targetDir, basePython) { if (result.error || result.status !== 0) { return null; } - return canRun(repairedBin, ["-V"]) ? repairedBin : null; + return canRunBackendPython(repairedBin) ? repairedBin : null; } function ensureBackendVenv() { for (const candidate of venvCandidates) { - if (fs.existsSync(candidate) && canRun(candidate, ["-V"])) { + if (fs.existsSync(candidate) && canRunBackendPython(candidate)) { persistSelectedVenv(candidate); return candidate; }