pypa/pip · error · OSError

"egg_name" is empty. This likely means no egg could be found

Error message

"egg_name" is empty. This likely means no egg could be found from the "module_path".

What it means

Raised as OSError by ZipProvider._extract_resource() when self.egg_name is empty during the extraction of a zipped resource. This is the second guard inside extraction (after the WRITE_SUPPORT check): extraction computes a cache path from egg_name and the zip-relative parts, so an empty egg_name makes cache path computation meaningless. egg_name is empty because EggProvider._setup_prefix found no egg-named ancestor among the module_path parents.

Source

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

        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)
            utime(tmpnam, (timestamp, timestamp))
            manager.postprocess(tmpnam, real_path)

            try:
                rename(tmpnam, real_path)

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Read the resource as bytes (resource_string/resource_stream) instead of requesting an extracted filename.
  2. Package the archive as an .egg or ensure EGG-INFO metadata exists so egg_name is populated.
  3. Use importlib.resources (files()/as_file()) which handles zip-backed extraction without egg naming.

Example fix

// before
path = pkg_resources.resource_filename('mymod', 'data.bin')  # OSError: egg_name empty

// after
data = pkg_resources.resource_string('mymod', 'data.bin')  # no egg_name needed
Defensive patterns

Strategy: validation

Validate before calling

import pkg_resources

def safe_extract_or_read(module, name):
    provider = pkg_resources.get_provider(module)
    if not getattr(provider, 'egg_name', None):
        return ('bytes', pkg_resources.resource_string(module, name))
    return ('path', pkg_resources.resource_filename(module, name))

Type guard

def provider_has_egg_name(provider) -> bool:
    return bool(getattr(provider, 'egg_name', None))

Try / catch

try:
    path = pkg_resources.resource_filename(pkg, name)
except OSError as e:
    if 'egg_name' in str(e) and 'empty' in str(e):
        data = pkg_resources.resource_string(pkg, name)
    else:
        raise

Prevention

When it happens

Trigger: Calling resource_filename()/get_resource_filename() (or any API that forces extraction) on a module inside a zip archive that is not recognized as an egg, so egg_name is None/empty and the cache path cannot be derived.

Common situations: Zipimporting a plain .zip or .pyz (zipapp) and requesting a filesystem path for a resource; the archive lacks egg naming conventions so _setup_prefix never calls _set_egg.

Related errors


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