pypa/pip · error · ValueError
Unknown CSIDL name
Error message
Unknown CSIDL name: {csidl_name} What it means
Raised as ValueError in get_win_folder_from_env_vars() at line 207-208 when the csidl_name is not one of the three recognized CSIDL constants (CSIDL_APPDATA, CSIDL_COMMON_APPDATA, CSIDL_LOCAL_APPDATA). The function maps CSIDL names to Windows environment variables; an unmapped name means the caller passed an unsupported CSIDL identifier.
Solutions
- Only pass valid CSIDL names: 'CSIDL_APPDATA', 'CSIDL_COMMON_APPDATA', 'CSIDL_LOCAL_APPDATA'.
- Use the top-level get_win_folder() dispatcher which routes to the correct backend (registry, ctypes, or env vars).
- Check _KNOWN_FOLDER_GUIDS keys for the full set of supported names when using the ctypes backend.
- Avoid calling get_win_folder_from_env_vars directly; it is an internal backend function.
Example fix
// before
get_win_folder_from_env_vars('CSIDL_PERSONAL')
# ValueError: Unknown CSIDL name: CSIDL_PERSONAL
// after
from pip._vendor.platformdirs.windows import get_win_folder
folder = get_win_folder('CSIDL_PERSONAL') # routes to correct backend Defensive patterns
Strategy: validation
Validate before calling
VALID_CSIDL_ENV = {'CSIDL_APPDATA', 'CSIDL_COMMON_APPDATA', 'CSIDL_LOCAL_APPDATA'}
def is_env_backed_csidl(csidl_name: str) -> bool:
return csidl_name in VALID_CSIDL_ENV Type guard
VALID_CSIDL = {'CSIDL_APPDATA', 'CSIDL_COMMON_APPDATA', 'CSIDL_LOCAL_APPDATA',
'CSIDL_PERSONAL', 'CSIDL_DOWNLOADS', 'CSIDL_MYPICTURES', 'CSIDL_MYVIDEO', 'CSIDL_MYMUSIC', 'CSIDL_PROGRAMS'}
def is_known_csidl(name: str) -> bool:
return name in VALID_CSIDL
Try / catch
try:
folder = get_win_folder_from_env_vars(csidl_name)
except ValueError:
folder = get_win_folder(csidl_name) # try full dispatcher
Prevention
- Use get_win_folder() dispatcher instead of calling get_win_folder_from_env_vars directly.
- Validate CSIDL names against known constants before passing to backend functions.
- Reference _KNOWN_FOLDER_GUIDS for the complete set of supported names.
When it happens
Trigger: Calling get_win_folder_from_env_vars with a csidl_name not in the {CSIDL_APPDATA, CSIDL_COMMON_APPDATA, CSIDL_LOCAL_APPDATA} mapping. This can happen via get_win_folder() -> _resolve_win_folder() chain when an unsupported CSIDL name is requested on a system using the env-var fallback strategy.
Common situations: Passing an incorrect CSIDL constant; internal platformdirs code requesting a folder type that the env-var backend doesn't support; corrupted or monkeypatched CSIDL constants; using the wrong backend function for the requested folder.
Related errors
- SHGetKnownFolderPath returned NULL for
- should only be used on Unix
- Unset environment variable
- non-local file URIs are not supported on this platform
- Can not perform a '--user' install. User site-packages are…
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/866fabc2db4fa203.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/platformdirs/windows.py:208
def site_runtime_dir(self) -> str:
"""Runtime directory shared by users, same as `user_runtime_dir`."""
return self.user_runtime_dir
def get_win_folder_from_env_vars(csidl_name: str) -> str:
"""Get folder from environment variables."""
result = get_win_folder_if_csidl_name_not_env_var(csidl_name)
if result is not None:
return result
env_var_name = {
"CSIDL_APPDATA": "APPDATA",
"CSIDL_COMMON_APPDATA": "ALLUSERSPROFILE",
"CSIDL_LOCAL_APPDATA": "LOCALAPPDATA",
}.get(csidl_name)
if env_var_name is None:
msg = f"Unknown CSIDL name: {csidl_name}"
raise ValueError(msg)
result = os.environ.get(env_var_name)
if result is None:
msg = f"Unset environment variable: {env_var_name}"
raise ValueError(msg)
return result
def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None: # ruff:ignore[too-many-return-statements]
"""Get a folder for a CSIDL name that does not exist as an environment variable."""
if csidl_name == "CSIDL_PERSONAL":
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Documents") # ruff:ignore[os-path-join]
if csidl_name == "CSIDL_DOWNLOADS":
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Downloads") # ruff:ignore[os-path-join]
if csidl_name == "CSIDL_MYPICTURES":
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Pictures") # ruff:ignore[os-path-join]
View on GitHub (pinned to f399c37189)