pypa/pip · error · ExceptionGroup

invalid or unparsed metadata

Error message

invalid or unparsed metadata

What it means

Re-raised as ExceptionGroup('invalid or unparsed metadata') by Metadata.from_email after from_raw has already collected individual InvalidMetadata exceptions. It bundles all field-level problems (invalid values, unparsed fields, type mismatches) into one group so callers see every defect rather than just the first.

Source

Thrown at src/pip/_vendor/packaging/metadata.py:843

        If *validate* is true, the metadata will be validated. All exceptions
        related to validation will be gathered and raised as an :class:`ExceptionGroup`.
        """
        raw, unparsed = parse_email(data)

        if validate:
            with _ErrorCollector().on_exit("unparsed") as collector:
                for unparsed_key in unparsed:
                    if unparsed_key in _EMAIL_TO_RAW_MAPPING:
                        message = f"{unparsed_key!r} has invalid data"
                    else:
                        message = f"unrecognized field: {unparsed_key!r}"
                    collector.error(InvalidMetadata(unparsed_key, message))

        try:
            return cls.from_raw(raw, validate=validate)
        except ExceptionGroup as exc_group:
            raise ExceptionGroup(
                "invalid or unparsed metadata", exc_group.exceptions
            ) from None

    metadata_version: _Validator[_MetadataVersion] = _Validator()
    """:external:ref:`core-metadata-metadata-version`
    (required; validated to be a valid metadata version)"""
    # `name` is not normalized/typed to NormalizedName so as to provide access to
    # the original/raw name.
    name: _Validator[str] = _Validator()
    """:external:ref:`core-metadata-name`
    (required; validated using :func:`~packaging.utils.canonicalize_name` and its
    *validate* parameter)"""
    version: _Validator[version_module.Version] = _Validator()
    """:external:ref:`core-metadata-version` (required)"""
    dynamic: _Validator[list[str] | None] = _Validator(
        added="2.2",
    )
    """:external:ref:`core-metadata-dynamic`

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Inspect exc.exceptions: each is an InvalidMetadata keyed by field; fix them one by one.
  2. Run twine check / build locally to surface all metadata issues before publishing.
  3. Pass validate=False if you only need best-effort parsing, then handle unparsed fields manually.
  4. Generate metadata with a conformant backend (setuptools, hatchling, flit) rather than hand-writing METADATA.

Example fix

# before
md = Metadata.from_email(raw, validate=True)
# after
try:
    md = Metadata.from_email(raw, validate=True)
except ExceptionGroup as eg:
    for sub in eg.exceptions:
        print(sub)
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

def validate_metadata(raw):
    try:
        Metadata.from_email(raw, validate=True)
        return []
    except ExceptionGroup as eg:
        return eg.exceptions

Try / catch

try:
    md = Metadata.from_email(raw, validate=True)
except ExceptionGroup as eg:
    for sub in eg.exceptions:
        print(f'{sub.field}: {sub}')  # InvalidMetadata has .field
    raise

Prevention

When it happens

Trigger: Calling from_email on METADATA with validate=True when fields are malformed (bad version, duplicate keys, invalid classifier, unknown fields, etc.). Any case where from_raw raises ExceptionGroup of InvalidMetadata instances.

Common situations: Consuming third-party package metadata; validating pyproject during build; CI linting wheels with twine check.

Related errors


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