pypa/pip · error · OSError

"os.mkdir" not supported on this platform.

Error message

"os.mkdir" not supported on this platform.

What it means

Raised as OSError from _bypass_ensure_directory when the global WRITE_SUPPORT flag is falsy on the current platform. WRITE_SUPPORT is set to None on environments where os.mkdir is unavailable (notably Google App Engine standard), so the sandbox-bypassing directory creation helper refuses to run.

Source

Thrown at src/pip/_vendor/pkg_resources/__init__.py:3510

    types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob))))
    for t in types:
        if t in registry:
            return registry[t]
    # _find_adapter would previously return None, and immediately be called.
    # So we're raising a TypeError to keep backward compatibility if anyone depended on that behaviour.
    raise TypeError(f"Could not find adapter for {registry} and {ob}")


def ensure_directory(path: StrOrBytesPath):
    """Ensure that the parent directory of `path` exists"""
    dirname = os.path.dirname(path)
    os.makedirs(dirname, exist_ok=True)


def _bypass_ensure_directory(path):
    """Sandbox-bypassing version of ensure_directory()"""
    if not WRITE_SUPPORT:
        raise OSError('"os.mkdir" not supported on this platform.')
    dirname, filename = split(path)
    if dirname and filename and not isdir(dirname):
        _bypass_ensure_directory(dirname)
        try:
            mkdir(dirname, 0o755)
        except FileExistsError:
            pass


def split_sections(s: _NestedStr) -> Iterator[tuple[str | None, list[str]]]:
    """Split a string or iterable thereof into (section, content) pairs

    Each ``section`` is a stripped version of the section header ("[section]")
    and each ``content`` is a list of stripped lines excluding blank lines and
    comment-only lines.  If there are any such lines before the first section
    header, they're returned in a first ``section`` of ``None``.
    """
    section = None

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Move off the restricted platform/runtime (e.g. GAE standard -> a runtime with full filesystem access) if you need directory creation.
  2. Pre-create the target directories out-of-band so _bypass_ensure_directory finds them and skips mkdir.
  3. Avoid the code path that triggers script/cache writing, or pin to a setuptools/pkg_resources version compatible with your sandbox.

Example fix

# before
# running on GAE standard -> OSError: "os.mkdir" not supported

# after
import os
os.makedirs('/tmp/myapp/cache', exist_ok=True)  # pre-create outside sandbox
# configure pkg_resources to use this writable dir as cache
Defensive patterns

Strategy: type-guard

Validate before calling

from pip._vendor.pkg_resources import WRITE_SUPPORT
if WRITE_SUPPORT is None:
    raise RuntimeError('mkdir unavailable on this platform; pre-create dirs')
_bypass_ensure_directory(path)

Type guard

def can_write() -> bool:
    from pip._vendor.pkg_resources import WRITE_SUPPORT
    return WRITE_SUPPORT is not None

Try / catch

try:
    _bypass_ensure_directory(path)
except OSError as e:
    if 'os.mkdir' not in str(e):
        raise
    # pre-create directory out of band

Prevention

When it happens

Trigger: Running pkg_resources code that calls _bypass_ensure_directory (used for creating parent directories of scripts/cache) on a platform where os.mkdir is not available, e.g. GAE standard sandbox or a locked-down runtime that strips os.mkdir.

Common situations: Deploying an app that imports pkg_resources on Google App Engine, or running in a restricted sandbox that deletes os.mkdir; the helper is invoked when installing/writing scripts or metadata.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/7fc0eb6a23dd8a86.json. Report an issue: GitHub.