pypa/pip · error · PEP723Exception
Multiple {name!r} blocks found in {scriptfile!r}
Error message
Multiple {name!r} blocks found in {scriptfile!r} What it means
Raised by pep723_metadata() when a Python script contains more than one PEP 723 `# /// script` metadata block. PEP 723 (inline script metadata) allows exactly one such block per script; the regex at pep723.py:6 finds multiple matching blocks of type 'script' and pip refuses to guess which one applies.
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 d7d0d0a394)
Solutions
- Open the script and delete all but one `# /// script` ... `# ///` block, keeping the one with the correct dependencies.
- Merge the dependencies from the duplicate blocks into a single block if both are needed.
- Re-run `pip run <script>` (or the consuming command) to confirm only one block remains.
Example fix
# before (two blocks) # /// script # dependencies = ["requests"] # /// # /// script # dependencies = ["rich"] # /// # after (merged) # /// script # dependencies = ["requests", "rich"] # ///
Defensive patterns
Strategy: validation
Validate before calling
import re
PEP723_RE = r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$"
def assert_single_script_block(scriptfile: str) -> None:
with open(scriptfile, encoding="utf8") as f:
script = f.read()
matches = [m for m in re.finditer(PEP723_RE, script) if m.group("type") == "script"]
if len(matches) > 1:
raise ValueError(f"{scriptfile} has {len(matches)} PEP 723 script blocks; expected 1") Type guard
null
Try / catch
from pip._internal.req.pep723 import pep723_metadata, PEP723Exception
try:
meta = pep723_metadata(scriptfile)
except PEP723Exception as e:
if e.msg.startswith("Multiple"):
# prompt user to dedupe blocks
...
raise Prevention
- Keep exactly one `# /// script` block per script.
- When merging scripts, combine dependencies into a single block.
- Lint scripts in CI to flag duplicate PEP 723 blocks.
When it happens
Trigger: A .py file passed to `pip run` (or PEP 723 processing) that has two `# /// script` ... `# ///` sections, e.g. from concatenating two scripts or a botched merge. The filter at pep723.py:21-23 yields len(matches) > 1.
Common situations: Merging two PEP 723 scripts without removing one block. A template/boilerplate tool injecting a second block. Copy-pasting a script that already had a block into another that also had one.
Related errors
- Failed to parse TOML in {scriptfile!r}
- File does not contain {name!r} metadata: {scriptfile!r}
- --requirements-from-script can only be given once
- <dynamic: PEP723 exception message (exc.msg)>
- [dependency-groups] resolution failed for '{groupname}' from
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/5de8e2668b112dc7.json.
Report an issue: GitHub.