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

  1. Only pass valid CSIDL names: 'CSIDL_APPDATA', 'CSIDL_COMMON_APPDATA', 'CSIDL_LOCAL_APPDATA'.
  2. Use the top-level get_win_folder() dispatcher which routes to the correct backend (registry, ctypes, or env vars).
  3. Check _KNOWN_FOLDER_GUIDS keys for the full set of supported names when using the ctypes backend.
  4. 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

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


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)