pypa/pip · error · OSError
"os.rename" and "os.unlink" are not supported on this…
Error message
"os.rename" and "os.unlink" are not supported on this platform
What it means
Raised as OSError by ZipProvider._extract_resource() when the module-level WRITE_SUPPORT flag is False. That flag is set False if `from os import mkdir, rename, unlink` raises ImportError at import time — which happens on platforms without these OS primitives (e.g. Google App Engine classic sandbox). Extraction requires os.rename/os.unlink to atomically write temp files, so it is unsupported.
Solutions
- Avoid resource_filename()/extraction on write-restricted platforms; use resource_stream()/resource_string() to read directly.
- Pre-extract resources to disk at deploy/build time so no runtime extraction is needed.
- Move to a runtime with full os support, or use importlib.resources which can serve zip contents without extraction.
Example fix
// before
# on a platform without os.rename/os.unlink
path = resource_filename('mypkg', 'data.txt') # raises OSError
// after
# read directly from the archive, no extraction
stream = resource_stream('mypkg', 'data.txt') Defensive patterns
Strategy: fallback
Validate before calling
import os
try:
from os import mkdir, rename, unlink
WRITE_OK = True
except ImportError:
WRITE_OK = False
if not WRITE_OK:
# use stream-based access; extraction unavailable Try / catch
try:
path = resource_filename('pkg', name)
except OSError:
stream = resource_stream('pkg', name) # fallback: no extraction Prevention
- On write-restricted platforms, use resource_stream()/resource_string().
- Pre-extract resources at build time for sandboxed deployments.
- Avoid pkg_resources extraction on GAE/sandboxed runtimes.
When it happens
Trigger: Triggering resource extraction from a zip/egg on a platform where os.mkdir/os.rename/os.unlink are unavailable — historically Google App Engine's Python 2 sandbox or similar restricted runtimes.
Common situations: Deploying pkg_resources-based code to a restricted sandbox (GAE classic) that blocks filesystem write/rename/unlink; exotic embedded runtimes lacking full os support.
Related errors
- Can't change extraction path, files already extracted
- resource_filename() only supported for .egg, not .zip
- `base` parameter in `_fn` is `None`. Either override this…
- Can't perform this operation for loaders without…
- Can't perform this operation for unregistered loader type
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/bc534d593f74a2e4.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/pkg_resources/__init__.py:2042
size = zip_stat.file_size
# ymdhms+wday, yday, dst
date_time = zip_stat.date_time + (0, 0, -1)
# 1980 offset already done
timestamp = time.mktime(date_time)
return timestamp, size
# FIXME: 'ZipProvider._extract_resource' is too complex (12)
def _extract_resource(self, manager: ResourceManager, zip_path) -> str: # noqa: C901
if zip_path in self._index():
for name in self._index()[zip_path]:
last = self._extract_resource(manager, os.path.join(zip_path, name))
# return the extracted directory name
return os.path.dirname(last)
timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
if not WRITE_SUPPORT:
raise OSError(
'"os.rename" and "os.unlink" are not supported on this platform'
)
try:
if not self.egg_name:
raise OSError(
'"egg_name" is empty. This likely means no egg could be found from the "module_path".'
)
real_path = manager.get_cache_path(self.egg_name, self._parts(zip_path))
if self._is_current(real_path, zip_path):
return real_path
outf, tmpnam = _mkstemp(
".$extract",
dir=os.path.dirname(real_path),
)
os.write(outf, self.loader.get_data(zip_path))
os.close(outf)View on GitHub (pinned to f399c37189)