{"id":"81ef9d79f6b8b66a","repo":"pypa/pip","slug":"invalid-section-heading","errorCode":null,"errorMessage":"Invalid section heading","messagePattern":"Invalid section heading","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/pkg_resources/__init__.py","lineNumber":3538,"sourceCode":"def split_sections(s: _NestedStr) -> Iterator[tuple[str | None, list[str]]]:\n    \"\"\"Split a string or iterable thereof into (section, content) pairs\n\n    Each ``section`` is a stripped version of the section header (\"[section]\")\n    and each ``content`` is a list of stripped lines excluding blank lines and\n    comment-only lines.  If there are any such lines before the first section\n    header, they're returned in a first ``section`` of ``None``.\n    \"\"\"\n    section = None\n    content = []\n    for line in yield_lines(s):\n        if line.startswith(\"[\"):\n            if line.endswith(\"]\"):\n                if section or content:\n                    yield section, content\n                section = line[1:-1].strip()\n                content = []\n            else:\n                raise ValueError(\"Invalid section heading\", line)\n        else:\n            content.append(line)\n\n    # wrap up last segment\n    yield section, content\n\n\ndef _mkstemp(*args, **kw):\n    old_open = os.open\n    try:\n        # temporarily bypass sandboxing\n        os.open = os_open\n        return tempfile.mkstemp(*args, **kw)\n    finally:\n        # and then put it back\n        os.open = old_open\n\n","sourceCodeStart":3520,"sourceCodeEnd":3556,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/pkg_resources/__init__.py#L3520-L3556","documentation":"Raised as ValueError from split_sections when a line begins with '[' but does not end with ']'. split_sections parses INI-like section headers ('[name]'); a line that opens a bracket without closing it is treated as a malformed section heading.","triggerScenarios":"Calling split_sections (directly or via parse_map) on text containing a line like '[console_scripts' (missing closing bracket), or a line beginning with '[' that is actually data with an embedded bracket.","commonSituations":"Hand-edited entry_points.txt or requires.txt with a typo in a section header, or data that legitimately starts with '[' but was not meant as a section (and is not bracket-balanced).","solutions":["Fix the malformed header so it is '[group]' with matching brackets.","If the line is genuine content starting with '[', escape or restructure it so it does not look like a section.","Validate the file as valid INI (configparser) before feeding it to split_sections."],"exampleFix":"# before (entry_points.txt)\n[console_scripts\nfoo = mod:fn\n\n# after\n[console_scripts]\nfoo = mod:fn","handlingStrategy":"validation","validationCode":"def balanced_section(line: str) -> bool:\n    s = line.strip()\n    return not s.startswith('[') or s.endswith(']')\nif all(balanced_section(l) for l in text.splitlines()):\n    list(split_sections(text))","typeGuard":"def is_valid_section_line(line: str) -> bool:\n    s = line.strip()\n    return not s.startswith('[') or (s.startswith('[') and s.endswith(']'))","tryCatchPattern":"try:\n    sections = list(split_sections(text))\nexcept ValueError as e:\n    if 'Invalid section heading' in str(e):\n        # fix the unmatched bracket, then retry\n        ...\n    raise","preventionTips":["Validate entry_points/required files as INI before parsing.","Generate section files with configparser.write()."],"tags":["python","pkg-resources","config","metadata","parsing"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}