fix(python): sanitize environment to prevent PYTHONHOME contamination (#664)

* fix(python): sanitize environment to prevent PYTHONHOME contamination

Fixes #176 (ACS-33): Ollama embedding download fails with 'Could not find
platform independent libraries <prefix>' error on Windows.

Root cause: When spawning Python subprocesses, the environment was not
sanitized. If users had PYTHONHOME set (common with Anaconda, corporate
Python installs, or embedded Python), the spawned Python couldn't find
its standard library.

Changes:
- Update getPythonEnv() to build complete env that excludes PYTHONHOME
- Pass sanitized env to spawn() in executeOllamaDetector() (2 locations)
- Pass sanitized env to spawn() in memory-service.ts executeQuery()
- Use sanitized env as base in executeSemanticQuery()

This follows the same pattern already used in agent-process.ts for
spawning agent Python processes.

* fix: address code review feedback

- Make PYTHONHOME check case-insensitive for Windows compatibility
- Fix type annotation in memory-service.ts (Record<string, string>)
This commit is contained in:
Michael Ludlow
2026-01-05 02:05:43 -05:00
committed by GitHub
parent eeef8a3d4a
commit 65f608986b
3 changed files with 37 additions and 11 deletions
@@ -25,7 +25,7 @@ import {
} from '../memory-service';
import { validateOpenAIApiKey } from '../api-validation-service';
import { parsePythonCommand } from '../python-detector';
import { getConfiguredPythonPath } from '../python-env-manager';
import { getConfiguredPythonPath, pythonEnvManager } from '../python-env-manager';
import { openTerminalWithCommand } from './claude-code-handlers';
/**
@@ -296,6 +296,9 @@ async function executeOllamaDetector(
let resolved = false;
const proc = spawn(pythonExe, args, {
stdio: ['ignore', 'pipe', 'pipe'],
// Use sanitized Python environment to prevent PYTHONHOME contamination
// Fixes "Could not find platform independent libraries" error on Windows
env: pythonEnvManager.getPythonEnv(),
});
let stdout = '';
@@ -769,6 +772,9 @@ export function registerMemoryHandlers(): void {
const proc = spawn(pythonExe, args, {
stdio: ['ignore', 'pipe', 'pipe'],
timeout: 600000, // 10 minute timeout for large models
// Use sanitized Python environment to prevent PYTHONHOME contamination
// Fixes "Could not find platform independent libraries" error on Windows
env: pythonEnvManager.getPythonEnv(),
});
let stdout = '';
+5 -2
View File
@@ -12,7 +12,7 @@ import * as path from 'path';
import * as fs from 'fs';
import { app } from 'electron';
import { findPythonCommand, parsePythonCommand } from './python-detector';
import { getConfiguredPythonPath } from './python-env-manager';
import { getConfiguredPythonPath, pythonEnvManager } from './python-env-manager';
import { getMemoriesDir } from './config-paths';
import type { MemoryEpisode } from '../shared/types';
@@ -134,6 +134,8 @@ async function executeQuery(
const proc = spawn(pythonExe, fullArgs, {
stdio: ['ignore', 'pipe', 'pipe'],
timeout,
// Use sanitized Python environment to prevent PYTHONHOME contamination
env: pythonEnvManager.getPythonEnv(),
});
let stdout = '';
@@ -193,7 +195,8 @@ async function executeSemanticQuery(
const [pythonExe, baseArgs] = parsePythonCommand(pythonCmd);
// Build environment with embedder configuration
const env: Record<string, string | undefined> = { ...process.env };
// Start with sanitized Python env to prevent PYTHONHOME contamination
const env: Record<string, string> = { ...pythonEnvManager.getPythonEnv() };
// Set the embedder provider
env.GRAPHITI_EMBEDDER_PROVIDER = embedderConfig.provider;
+25 -8
View File
@@ -619,23 +619,40 @@ if sys.version_info >= (3, 12):
/**
* Get environment variables that should be set when spawning Python processes.
* This ensures Python finds the bundled packages or venv packages.
*
* IMPORTANT: This returns a COMPLETE environment (based on process.env) with
* problematic Python variables removed. This fixes the "Could not find platform
* independent libraries <prefix>" error on Windows when PYTHONHOME is set.
*
* @see https://github.com/AndyMik90/Auto-Claude/issues/176
*/
getPythonEnv(): Record<string, string> {
const env: Record<string, string> = {
// Start with process.env but explicitly remove problematic Python variables
// PYTHONHOME causes "Could not find platform independent libraries" when set
// to a different Python installation than the one we're spawning
const baseEnv: Record<string, string> = {};
for (const [key, value] of Object.entries(process.env)) {
// Skip PYTHONHOME - it causes the "platform independent libraries" error
// Use case-insensitive check for Windows compatibility (env vars are case-insensitive on Windows)
// Skip undefined values (TypeScript type guard)
if (key.toUpperCase() !== 'PYTHONHOME' && value !== undefined) {
baseEnv[key] = value;
}
}
// Apply our Python configuration on top
return {
...baseEnv,
// Don't write bytecode - not needed and avoids permission issues
PYTHONDONTWRITEBYTECODE: '1',
// Use UTF-8 encoding
PYTHONIOENCODING: 'utf-8',
// Disable user site-packages to avoid conflicts
PYTHONNOUSERSITE: '1',
// Override PYTHONPATH if we have bundled packages
...(this.sitePackagesPath ? { PYTHONPATH: this.sitePackagesPath } : {}),
};
// Set PYTHONPATH to our site-packages
if (this.sitePackagesPath) {
env.PYTHONPATH = this.sitePackagesPath;
}
return env;
}
/**