{"record":{"id":"5ade1208c09f7409","repo":"windmill-labs/windmill","slug":"cannot-convert-osstring-to-string","errorCode":null,"errorMessage":"Cannot convert OsString to String","messagePattern":"Cannot convert OsString to String","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/python_executor.rs","lineNumber":547,"sourceCode":"    conn: &Connection,\n) -> windmill_common::error::Result<()> {\n    // It is guranteed that additional_python_paths only contains paths within windmill/cache/\n    // All other paths you would usually expect in PYTHONPATH are NOT included. These are added in downstream\n    //\n    //                      <PackageName, Vec<GlobalPath>>\n    let mut lookup_table: HashMap<String, Vec<String>> = HashMap::new();\n    // e.g.: <\"requests\", [\"/tmp/windmill/cache/python_311/requests==1.0.0\"]>\n    for path in additional_python_paths.iter() {\n        for entry in fs::read_dir(&path)? {\n            let entry = entry?;\n            // Ignore all files, we only need directories.\n            // We cannot merge files.\n            if entry.file_type()?.is_dir() {\n                // Short name, e.g.: requests\n                let name = entry\n                    .file_name()\n                    .to_str()\n                    .ok_or(anyhow::anyhow!(\"Cannot convert OsString to String\"))?\n                    .to_owned();\n\n                if name == \"bin\" || name == \"__pycache__\" || name.contains(\"dist-info\") {\n                    continue;\n                }\n\n                if let Some(existing_paths) = lookup_table.get_mut(&name) {\n                    tracing::debug!(\n                        \"Found existing package name: {:?} in {}\",\n                        entry.file_name(),\n                        path\n                    );\n                    existing_paths.push(path.to_owned())\n                } else {\n                    lookup_table.insert(name, vec![path.to_owned()]);\n                }\n            }\n        }","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/python_executor.rs#L529-L565","documentation":"During Python venv postinstall, Windmill walks the site-packages directory to relink/collect package folders. Each entry's file_name() is an OsString that must be valid UTF-8 to become a Rust String; the code raises \"Cannot convert OsString to String\" when a directory name contains invalid UTF-8 bytes. Python package names are essentially always ASCII, so this almost always indicates a corrupted or foreign directory inside site-packages.","triggerScenarios":"Running a Python job whose dependency install triggers the postinstall step while a directory inside the venv's site-packages has a non-UTF-8 name (bad bytes from a failed download, a manually extracted tarball, or filenames created with a non-UTF-8 locale).","commonSituations":"A venv cache corrupted by disk errors or interrupted extraction; someone manually placed a folder with exotic characters into site-packages on the worker host; a shared/NFS mount with a different filesystem encoding; rebuilding worker caches from a damaged S3 tarball.","solutions":["List site-packages to find the non-UTF-8 directory: find <venv>/lib/python*/site-packages -maxdepth 1 -type d | grep -P '[^\\x00-\\x7F]' and delete or rename it.","Delete the corrupted venv/cache directory so the next job reinstalls it cleanly.","Check the S3 venv tarball (enterprise) for corrupt entries and re-upload a fresh one, or disable the tarball cache for that venv.","Ensure the worker's locale/filesystem is UTF-8 (e.g. LANG=C.UTF-8) so tooling doesn't create mis-encoded names."],"exampleFix":"# before (inspect)\nls <venv>/lib/python3.11/site-packages\n# after (remove the corrupt entry and let it reinstall)\nfind <venv>/lib/python3.11/site-packages -maxdepth 1 -type d -name '*[^[:print:]]*' -exec rm -rf {} +\n# or simply:\nrm -rf <venv>","handlingStrategy":"validation","validationCode":"# run on the worker host before scheduling Python jobs\nbad=$(find /root/.cache/windmill -path '*/site-packages/*' -maxdepth 8 -type d 2>/dev/null | grep -P '[^\\x00-\\x7F]'); [ -z \"$bad\" ] && echo OK || echo \"$bad\"","typeGuard":null,"tryCatchPattern":"// worker-side log handling: treat as cache corruption and wipe the venv\nif (err.message.includes('Cannot convert OsString to String')) {\n  fs.rmSync(venvPath, { recursive: true, force: true }); // next job reinstalls cleanly\n}","preventionTips":["Set LANG=C.UTF-8 on worker hosts so tooling never creates mis-encoded filenames","Periodically validate/refresh the venv cache; delete venvs after worker crashes","Verify S3 venv tarballs are built and extracted with UTF-8-safe tooling"],"tags":["python","filesystem","encoding"],"backgroundTag":"invalid-utf8-path","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}