pypa/pip · error · ParserSyntaxError
Invalid quoted string
Error message
Invalid quoted string
What it means
When parsing a PEP 508 environment marker, _parse_marker_var encounters a QUOTED_STRING token and processes it via process_python_str, which calls ast.literal_eval. If the string cannot be safely evaluated (malformed quotes, invalid escape sequences), SyntaxError or ValueError is caught and ParserSyntaxError('Invalid quoted string') is raised with a span pointing at the offending token.
Source
Thrown at src/pip/_vendor/packaging/_parser.py:378
marker_op = _parse_marker_op(tokenizer)
tokenizer.consume("WS")
marker_var_right = _parse_marker_var(tokenizer)
tokenizer.consume("WS")
return (marker_var_left, marker_op, marker_var_right)
def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: # noqa: RET503
"""
marker_var = VARIABLE | QUOTED_STRING
"""
if tokenizer.check("VARIABLE"):
return process_env_var(tokenizer.read().text.replace(".", "_"))
elif tokenizer.check("QUOTED_STRING"):
token = tokenizer.read()
try:
return process_python_str(token.text)
except (SyntaxError, ValueError) as exc:
raise ParserSyntaxError(
"Invalid quoted string",
source=tokenizer.source,
span=(token.position, token.position + len(token.text)),
) from exc
else:
tokenizer.raise_syntax_error(
message="Expected a marker variable or quoted string"
)
def process_env_var(env_var: str) -> Variable:
if env_var in ("platform_python_implementation", "python_implementation"):
return Variable("platform_python_implementation")
else:
return Variable(env_var)
def process_python_str(python_str: str) -> Value:View on GitHub (pinned to f399c37189)
Solutions
- Fix the quoting in the marker expression so every quoted string has matching opening/closing quotes of the same type
- Use consistent quote style (single quotes) throughout marker expressions
- Validate requirement strings with Requirement() early during config loading to surface errors immediately
Example fix
# before
from packaging.requirements import Requirement
req = Requirement('django>=4.0 ; python_version >= "3.8') # unclosed quote
# after
req = Requirement("django>=4.0 ; python_version >= '3.8'") # properly quoted Defensive patterns
Strategy: try-catch
Validate before calling
def validate_marker_quoting(marker_str: str) -> bool:
for quote_char in ('"', "'"):
if marker_str.count(quote_char) % 2 != 0:
return False
return True Try / catch
from packaging.requirements import Requirement, InvalidRequirement
from packaging._tokenizer import ParserSyntaxError
try:
req = Requirement(req_string)
except (InvalidRequirement, ParserSyntaxError) as e:
print(f"Invalid requirement syntax: {e}") Prevention
- Validate requirement strings at config load time
- Use consistent single-quote style in markers
- Lint requirements files for syntax errors
- Test programmatic requirement string construction with unit tests
When it happens
Trigger: Calling parse_marker(), parse_requirement(), or constructing Requirement/Marker objects with a specifier containing a malformed quoted string in an environment marker, e.g. python_version >= "3.8 (missing closing quote).
Common situations: Typos in requirements.txt or pyproject.toml markers. Programmatically building requirement strings with unescaped or mismatched quotes. Copy-paste errors in dependency specifiers.
Related errors
- Cannot serialize marker value containing both quote characte
- Undefined {op!r} on {lhs!r} and {rhs!r}.
- {str(e)}
- invalid-egg-fragment
- Invalid requirement: {name.strip()!r}: {exc}
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/e0635fc69f0e31b4.
Report an issue: GitHub.