pypa/pip · error · ResolutionError
Script {script!r} not found in metadata at {self.egg_info!r}
Error message
Script {script!r} not found in metadata at {self.egg_info!r} What it means
Raised as a ResolutionError by Distribution.run_script() when the requested script_name does not correspond to an entry under EGG-INFO/scripts/ in the distribution's metadata. run_script() builds 'scripts/' + script_name and checks has_metadata(); if absent it refuses to exec. The distribution must therefore carry script files in its egg-info metadata for the name to resolve.
Source
Thrown at src/pip/_vendor/pkg_resources/__init__.py:1701
def resource_isdir(self, resource_name: str):
return self._isdir(self._fn(self.module_path, resource_name))
def metadata_isdir(self, name: str) -> bool:
return bool(self.egg_info and self._isdir(self._fn(self.egg_info, name)))
def resource_listdir(self, resource_name: str):
return self._listdir(self._fn(self.module_path, resource_name))
def metadata_listdir(self, name: str) -> list[str]:
if self.egg_info:
return self._listdir(self._fn(self.egg_info, name))
return []
def run_script(self, script_name: str, namespace: dict[str, Any]):
script = 'scripts/' + script_name
if not self.has_metadata(script):
raise ResolutionError(
"Script {script!r} not found in metadata at {self.egg_info!r}".format(
**locals()
),
)
script_text = self.get_metadata(script).replace('\r\n', '\n')
script_text = script_text.replace('\r', '\n')
script_filename = self._fn(self.egg_info, script)
namespace['__file__'] = script_filename
if os.path.exists(script_filename):
source = _read_utf8_with_fallback(script_filename)
code = compile(source, script_filename, 'exec')
exec(code, namespace, namespace)
else:
from linecache import cache
cache[script_filename] = (
len(script_text),View on GitHub (pinned to d7d0d0a394)
Solutions
- Verify the script exists first: `if dist.has_metadata('scripts/' + name): dist.run_script(name, ns)`.
- List available scripts via `dist.metadata_listdir('scripts')` and use an exact name from that list.
- Prefer EntryPoint.load() over run_script() for invoking console entry points, which is the modern, metadata-driven path.
Example fix
// before
dist.run_script('manage', ns) # ResolutionError if 'scripts/manage' missing
// after
ep = dist.get_entry_info('console_scripts', 'manage')
ep.load(require=False)(ns) # use the entry point instead Defensive patterns
Strategy: validation
Validate before calling
import pkg_resources
def safe_run_script(dist, script_name, namespace):
script_rel = 'scripts/' + script_name
if dist.has_metadata(script_rel):
return dist.run_script(script_name, namespace)
available = dist.metadata_listdir('scripts') if dist.egg_info else []
raise KeyError(f'{script_name!r} not in scripts/; available: {available}') Type guard
def script_exists(dist, script_name):
return dist.has_metadata('scripts/' + script_name) Try / catch
try:
dist.run_script(name, ns)
except pkg_resources.ResolutionError as e:
if 'not found in metadata' in str(e):
# script missing; list what is available
avail = dist.metadata_listdir('scripts')
raise KeyError(f'missing {name!r}; have {avail}') from e
raise Prevention
- Check has_metadata('scripts/' + name) before run_script().
- Prefer EntryPoint.load() for invoking console entry points.
- List scripts via metadata_listdir('scripts') to discover valid names.
When it happens
Trigger: Calling dist.run_script('my_script', namespace_dict) where 'my_script' is not present as EGG-INFO/scripts/my_script in that distribution's metadata (typo, wrong distribution, or scripts were never installed/packaged).
Common situations: Calling console-script entry points manually via run_script with the wrong name, a distribution installed without its scripts directory (stripped wheel, broken metadata), or a stale egg-info left after a version change.
Related errors
- Error decoding metadata for {self._wheel_name}: {e} in {name
- Expected str, Requirement, or Distribution
- `base` parameter in `_fn` is `None`. Either override this me
- No metadata except PKG-INFO is available
- Invalid group name
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/d1068abdae694a2d.json.
Report an issue: GitHub.