pypa/pip · error · PEP723Exception
Failed to parse TOML in {scriptfile!r}
Error message
Failed to parse TOML in {scriptfile!r} What it means
Raised by pep723_metadata() when the content inside a PEP 723 `# /// script` block cannot be parsed as valid TOML (pep723.py:34). The block's comment-stripped content is fed to tomllib.loads; any TOMLDecodeError (or other parse exception) is caught and re-raised as a PEP723Exception.
Source
Thrown at src/pip/_internal/req/pep723.py:35
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 fix the TOML inside the `# /// script` block: quote strings, balance brackets, use valid keys.
- Validate by extracting the block content and running `python -c "import tomllib; tomllib.loads(open('block.toml').read())"`.
- Ensure every line inside the block starts with `# ` (hash space) so the stripper at pep723.py:29 works.
- Avoid inline comments or TOML features your toolchain doesn't support.
Example fix
# before # /// script # dependencies = [requests] # /// # after # /// script # dependencies = ["requests"] # ///
Defensive patterns
Strategy: validation
Validate before calling
import re, tomllib
PEP723_RE = r"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\s(?P<content>(^#(| .*)$\s)+)^# ///$"
def validate_pep723_toml(scriptfile: str) -> dict:
with open(scriptfile, encoding="utf8") as f:
script = f.read()
m = next((m for m in re.finditer(PEP723_RE, script) if m.group("type") == "script"), None)
if m is None:
raise ValueError("no script block")
content = "".join(line[2:] if line.startswith("# ") else line[1:]
for line in m.group("content").splitlines(keepends=True))
try:
return tomllib.loads(content)
except tomllib.TOMLDecodeError as e:
raise ValueError(f"PEP 723 TOML invalid: {e}") from e Type guard
null
Try / catch
from pip._internal.req.pep723 import pep723_metadata, PEP723Exception
try:
meta = pep723_metadata(scriptfile)
except PEP723Exception as e:
if "Failed to parse TOML" in e.msg:
# surface the block to the user for editing
...
raise Prevention
- Quote all string values inside the PEP 723 block.
- Keep each line prefixed with `# ` so the stripper works.
- Validate the block's TOML in a pre-commit hook.
When it happens
Trigger: A script block with malformed TOML: missing quotes around values, unbalanced brackets, invalid keys, stray characters. e.g. `# dependencies = [requests]` (unquoted) or `# /// script` followed by `# bad = = toml`.
Common situations: Hand-editing the inline block and forgetting TOML quoting rules. Copy-pasting from a source that dropped quote characters. Tabs or unusual whitespace inside the block.
Related errors
- Multiple {name!r} blocks found 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/da80e8004849ff3b.json.
Report an issue: GitHub.