{"id":"5de8e2668b112dc7","repo":"pypa/pip","slug":"multiple-name-r-blocks-found-in-scriptfile-r","errorCode":null,"errorMessage":"Multiple {name!r} blocks found in {scriptfile!r}","messagePattern":"Multiple (.+?) blocks found in (.+?)","errorType":"exception","errorClass":"PEP723Exception","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/req/pep723.py","lineNumber":26,"sourceCode":"\nclass PEP723Exception(ValueError):\n    \"\"\"Raised to indicate a problem when parsing PEP 723 metadata from a script\"\"\"\n\n    def __init__(self, msg: str) -> None:\n        self.msg = msg\n\n\ndef pep723_metadata(scriptfile: str) -> dict[str, Any]:\n    with open(scriptfile, encoding=\"utf8\") as f:\n        script = f.read()\n\n    name = \"script\"\n    matches = list(\n        filter(lambda m: m.group(\"type\") == name, re.finditer(REGEX, script))\n    )\n\n    if len(matches) > 1:\n        raise PEP723Exception(f\"Multiple {name!r} blocks found in {scriptfile!r}\")\n    elif len(matches) == 1:\n        content = \"\".join(\n            line[2:] if line.startswith(\"# \") else line[1:]\n            for line in matches[0].group(\"content\").splitlines(keepends=True)\n        )\n        try:\n            metadata = tomllib.loads(content)\n        except Exception as exc:\n            raise PEP723Exception(f\"Failed to parse TOML in {scriptfile!r}\") from exc\n    else:\n        raise PEP723Exception(\n            f\"File does not contain {name!r} metadata: {scriptfile!r}\"\n        )\n\n    return metadata\n","sourceCodeStart":8,"sourceCodeEnd":42,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/req/pep723.py#L8-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (two blocks)\n# /// script\n# dependencies = [\"requests\"]\n# ///\n# /// script\n# dependencies = [\"rich\"]\n# ///\n# after (merged)\n# /// script\n# dependencies = [\"requests\", \"rich\"]\n# ///","handlingStrategy":"validation","validationCode":"import re\n\nPEP723_RE = r\"(?m)^# /// (?P<type>[a-zA-Z0-9-]+)$\\s(?P<content>(^#(| .*)$\\s)+)^# ///$\"\n\ndef assert_single_script_block(scriptfile: str) -> None:\n    with open(scriptfile, encoding=\"utf8\") as f:\n        script = f.read()\n    matches = [m for m in re.finditer(PEP723_RE, script) if m.group(\"type\") == \"script\"]\n    if len(matches) > 1:\n        raise ValueError(f\"{scriptfile} has {len(matches)} PEP 723 script blocks; expected 1\")","typeGuard":"null","tryCatchPattern":"from pip._internal.req.pep723 import pep723_metadata, PEP723Exception\n\ntry:\n    meta = pep723_metadata(scriptfile)\nexcept PEP723Exception as e:\n    if e.msg.startswith(\"Multiple\"):\n        # prompt user to dedupe blocks\n        ...\n    raise","preventionTips":["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."],"tags":["pep723","script","toml","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}