pypa/pip · error · PEP723Exception

Multiple blocks found in

Error message

Multiple {name!r} blocks found in {scriptfile!r}

What it means

PEP 723 inline script metadata uses exactly one '# /// script' fenced block in a Python script. pip's pep723_metadata() function found more than one matching block and raised PEP723Exception. A script must have at most one inline metadata block.

Solutions

  1. Search the script for all '# /// script' markers and keep only one
  2. Merge the dependencies from duplicate blocks into a single '# /// script' block
  3. Use a text editor or grep to locate the blocks: grep -n '# /// script' script.py

Example fix

# before — two blocks in script.py:
# /// script
# dependencies = ["requests"]
# ///
# ... later ...
# /// script
# dependencies = ["rich"]
# ///

# after — single merged block:
# /// script
# dependencies = ["requests", "rich"]
# ///
Defensive patterns

Strategy: validation

Validate before calling

import re

REGEX = r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$"

def count_script_blocks(filepath: str) -> int:
    with open(filepath) as f:
        script = f.read()
    return len([m for m in re.finditer(REGEX, script) if m.group("type") == "script"])

if count_script_blocks("script.py") > 1:
    print("Duplicate PEP 723 blocks detected — merge them")

Type guard

def has_single_pep723_block(filepath: str) -> bool:
    """Type guard: True if the file has exactly one '# /// script' block."""
    import re
    regex = r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$"
    with open(filepath) as f:
        matches = [m for m in re.finditer(regex, f.read()) if m.group("type") == "script"]
    return len(matches) == 1

Try / catch

from pip._internal.req.pep723 import pep723_metadata, PEP723Exception

try:
    meta = pep723_metadata("script.py")
except PEP723Exception as e:
    if "Multiple" in e.msg:
        print("Fix: merge duplicate '# /// script' blocks into one")
    else:
        raise

Prevention

When it happens

Trigger: A Python script passed to pip's PEP 723 support (e.g. pip run script.py) contains two separate '# /// script' ... '# ///' sections. This can happen when merging scripts or when an editor/tool inserts a second metadata block.

Common situations: Concatenating two scripts that each had their own metadata block. An IDE plugin or tooling that auto-generates a metadata block without checking for an existing one. Copy-paste of a dependencies section.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/5de8e2668b112dc7. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/req/pep723.py:26

class PEP723Exception(ValueError):
    """Raised to indicate a problem when parsing PEP 723 metadata from a script"""

    def __init__(self, msg: str) -> None:
        self.msg = msg


def pep723_metadata(scriptfile: str) -> dict[str, Any]:
    with open(scriptfile, encoding="utf8") as f:
        script = f.read()

    name = "script"
    matches = list(
        filter(lambda m: m.group("type") == name, re.finditer(REGEX, script))
    )

    if len(matches) > 1:
        raise PEP723Exception(f"Multiple {name!r} blocks found in {scriptfile!r}")
    elif len(matches) == 1:
        content = "".join(
            line[2:] if line.startswith("# ") else line[1:]
            for line in matches[0].group("content").splitlines(keepends=True)
        )
        try:
            metadata = tomllib.loads(content)
        except Exception as exc:
            raise PEP723Exception(f"Failed to parse TOML in {scriptfile!r}") from exc
    else:
        raise PEP723Exception(
            f"File does not contain {name!r} metadata: {scriptfile!r}"
        )

    return metadata

View on GitHub (pinned to f399c37189)