From 07ae1ef709ed22892fe1e9c8b21d936d7a7b91d4 Mon Sep 17 00:00:00 2001 From: Maxim Kosterin Date: Thu, 8 Jan 2026 15:04:13 +0100 Subject: [PATCH] Fix pydantic_core missing module error during packaging (#806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #684 ## Problem Users reported `ModuleNotFoundError: No module named 'pydantic_core._pydantic_core'` when running the packaged macOS app. This occurred because: 1. pydantic-core includes a compiled C extension (_pydantic_core.so) 2. During packaging, pip could attempt to build from source if no binary wheel found 3. Source builds could fail silently without a C compiler 4. The package would be marked as "installed" but missing the critical extension 5. pydantic_core was not in the critical packages verification list ## Solution This fix implements two changes: 1. **Force binary wheels for pydantic packages** - Added `--only-binary pydantic,pydantic-core` to pip install args - Prevents silent source build failures - Ensures compiled extensions are properly included 2. **Add pydantic_core to critical packages verification** - Added to both download-python.cjs verification checks (lines 712, 815) - Added to python-env-manager.ts verification (line 129) - Ensures packaging fails fast if pydantic_core is missing ## Testing The fix ensures that: - Packaging will fail if pydantic binary wheels aren't available - Both build-time and runtime verification check for pydantic_core - Users won't receive a broken package with missing dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.5 Co-authored-by: StillKnotKnown <192589389+StillKnotKnown@users.noreply.github.com> Co-authored-by: Alex <63423455+AlexMadera@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> --- apps/frontend/scripts/download-python.cjs | 6 ++++-- apps/frontend/src/main/python-env-manager.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/frontend/scripts/download-python.cjs b/apps/frontend/scripts/download-python.cjs index 86bc47b3..17f9abdf 100644 --- a/apps/frontend/scripts/download-python.cjs +++ b/apps/frontend/scripts/download-python.cjs @@ -610,11 +610,13 @@ function installPackages(pythonBin, requirementsPath, targetSitePackages) { // Install packages directly to target directory // --no-compile: Don't create .pyc files (saves space, Python will work without them) // --target: Install to specific directory + // --only-binary: Force binary wheels for pydantic (prevents silent source build failures) // Note: We intentionally DO use pip's cache to preserve built wheels for packages // like real_ladybug that must be compiled from source on Intel Mac (no PyPI wheel) const pipArgs = [ '-m', 'pip', 'install', '--no-compile', + '--only-binary', 'pydantic,pydantic-core', '--target', targetSitePackages, '-r', requirementsPath, ]; @@ -707,7 +709,7 @@ async function downloadPython(targetPlatform, targetArch, options = {}) { // Without this check, corrupted caches with missing packages would be accepted // Note: Same list exists in python-env-manager.ts - keep them in sync // This validation assumes traditional Python packages with __init__.py (not PEP 420 namespace packages) - const criticalPackages = ['claude_agent_sdk', 'dotenv']; + const criticalPackages = ['claude_agent_sdk', 'dotenv', 'pydantic_core']; const missingPackages = criticalPackages.filter(pkg => { const pkgPath = path.join(sitePackagesDir, pkg); // Check both directory and __init__.py for more robust validation @@ -810,7 +812,7 @@ async function downloadPython(targetPlatform, targetArch, options = {}) { // Verify critical packages were installed before creating marker (fixes #416) // Note: Same list exists in python-env-manager.ts - keep them in sync // This validation assumes traditional Python packages with __init__.py (not PEP 420 namespace packages) - const criticalPackages = ['claude_agent_sdk', 'dotenv']; + const criticalPackages = ['claude_agent_sdk', 'dotenv', 'pydantic_core']; const postInstallMissing = criticalPackages.filter(pkg => { const pkgPath = path.join(sitePackagesDir, pkg); const initFile = path.join(pkgPath, '__init__.py'); diff --git a/apps/frontend/src/main/python-env-manager.ts b/apps/frontend/src/main/python-env-manager.ts index bd31c72f..fc9a0c90 100644 --- a/apps/frontend/src/main/python-env-manager.ts +++ b/apps/frontend/src/main/python-env-manager.ts @@ -126,7 +126,7 @@ export class PythonEnvManager extends EventEmitter { // This fixes GitHub issue #416 where marker exists but packages are missing // Note: Same list exists in download-python.cjs - keep them in sync // This validation assumes traditional Python packages with __init__.py (not PEP 420 namespace packages) - const criticalPackages = ['claude_agent_sdk', 'dotenv']; + const criticalPackages = ['claude_agent_sdk', 'dotenv', 'pydantic_core']; // Check each package exists with valid structure (directory + __init__.py) const missingPackages = criticalPackages.filter((pkg) => {