pypa/pip · error · ValueError

SHGetKnownFolderPath returned NULL for

Error message

SHGetKnownFolderPath returned NULL for {csidl_name}

What it means

Raised after the ctypes resolver calls shell32.SHGetKnownFolderPath for a known GUID and the returned pointer is NULL. A NULL result means Windows itself could not resolve the folder, even though the GUID was valid. This typically indicates the folder is not registered, not present on the current system, or the user profile is incomplete.

Solutions

  1. Verify the user profile is complete (sign out/in or run 'systempropertiesadvanced' to rebuild profile folders).
  2. Run under an interactive user account rather than SYSTEM/LocalService where the known folder may be absent.
  3. Pre-create or redirect the missing known folder via the registry or Group Policy.
  4. Fall back to an adjacent folder (e.g. LOCALAPPDATA) if the specific folder is optional to your logic.

Example fix

try:
    folder = get_win_folder_via_ctypes('CSIDL_DOWNLOADS')
except ValueError:
    folder = os.path.join(os.environ['USERPROFILE'], 'Downloads')
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

null

Try / catch

try:
    folder = get_win_folder_via_ctypes(name)
except ValueError as e:
    if 'NULL' in str(e):
        folder = os.path.join(os.environ.get('USERPROFILE',''), 'Downloads')
    else:
        raise

Prevention

When it happens

Trigger: SHGetKnownFolderPath returns a NULL LPWSTR (path_ptr.value is None) at windows.py:358-362, e.g. requesting CSIDL_COMMON_PROGRAMS in a stripped-down Windows environment, a corrupted user profile, or running under a service account whose profile lacks the folder.

Common situations: Running pip/platformdirs in a container, Windows Server Core, or a locked-down account where the Downloads/Pictures folder is not materialized; redirected/roamed folders that failed to provision; a broken user profile after a migration.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/056b9b54b246cadf. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_vendor/platformdirs/windows.py:363

    kernel32.GetShortPathNameW.argtypes = [wintypes.LPWSTR, wintypes.LPWSTR, wintypes.DWORD]

    def resolve(csidl_name: str) -> str:
        folder_guid = _KNOWN_FOLDER_GUIDS.get(csidl_name)
        if folder_guid is None:
            msg = f"Unknown CSIDL name: {csidl_name}"
            raise ValueError(msg)

        guid = _GUID()
        ole32.CLSIDFromString(folder_guid, byref(guid))

        path_ptr = wintypes.LPWSTR()
        shell32.SHGetKnownFolderPath(byref(guid), _KF_FLAG_DONT_VERIFY, None, byref(path_ptr))
        result = path_ptr.value
        ole32.CoTaskMemFree(path_ptr)

        if result is None:
            msg = f"SHGetKnownFolderPath returned NULL for {csidl_name}"
            raise ValueError(msg)

        if any(ord(c) > 255 for c in result):  # ruff:ignore[magic-value-comparison]
            buf = create_unicode_buffer(1024)
            if kernel32.GetShortPathNameW(result, buf, 1024):
                result = buf.value

        return result

    return resolve


def get_win_folder_via_ctypes(csidl_name: str) -> str:
    """Get folder via :func:`SHGetKnownFolderPath`.

    See https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath.

    """
    return _build_get_win_folder_via_ctypes()(csidl_name)

View on GitHub (pinned to f399c37189)