nodejs/node · error · UndefinedComparison
Undefined {op!r} on {lhs!r} and {rhs!r}.
Error message
Undefined {op!r} on {lhs!r} and {rhs!r}. What it means
Raised by _eval_op (the core of packaging's environment-marker evaluation) when an operator token is neither a valid PEP 440 specifier prefix (for Specifier-based comparison) nor a key in the built-in _operators dict. PEP 508 environment markers like 'python_version >= "3.8"' are evaluated here; an unrecognized operator means the marker expression contains an operator the library cannot interpret.
Source
Thrown at tools/gyp/pylib/packaging/markers.py:120
"<=": operator.le,
"==": operator.eq,
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
}
def _eval_op(lhs: str, op: Op, rhs: str) -> bool:
try:
spec = Specifier("".join([op.serialize(), rhs]))
except InvalidSpecifier:
pass
else:
return spec.contains(lhs, prereleases=True)
oper: Optional[Operator] = _operators.get(op.serialize())
if oper is None:
raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.")
return oper(lhs, rhs)
def _normalize(*values: str, key: str) -> Tuple[str, ...]:
# PEP 685 – Comparison of extra names for optional distribution dependencies
# https://peps.python.org/pep-0685/
# > When comparing extra names, tools MUST normalize the names being
# > compared using the semantics outlined in PEP 503 for names
if key == "extra":
return tuple(canonicalize_name(v) for v in values)
# other environment markers don't have such standards
return values
def _evaluate_markers(markers: MarkerList, environment: Dict[str, str]) -> bool:
groups: List[List[bool]] = [[]]View on GitHub (pinned to 1b2de5e052)
Solutions
- Inspect the full marker string that triggered the error and locate the invalid operator.
- Correct the operator to a valid PEP 508 operator: ==, !=, <=, >=, <, >, ~=, in, not in.
- Upgrade the `packaging` library to a version that supports the marker syntax you are using.
- Report the malformed marker to the package maintainer if it comes from third-party metadata you do not control.
Example fix
# before (malformed marker in metadata) os_name ~=='posix' # after os_name == 'posix'
Defensive patterns
Strategy: try-catch
Validate before calling
# Validate marker operators before evaluation
from packaging.markers import Marker
_VALID_OPS = {'==', '!=', '<=', '>=', '<', '>', '~=', 'in', 'not in'}
# If constructing markers programmatically, ensure ops are in _VALID_OPS Type guard
def is_valid_marker(text: str) -> bool:
from packaging.markers import Marker, InvalidMarker
try:
Marker(text)
return True
except InvalidMarker:
return False Try / catch
from packaging.markers import UndefinedComparison
try:
result = Marker(text).evaluate()
except UndefinedComparison as e:
print(f'unsupported operator in marker: {e}')
result = True # safe default Prevention
- When writing environment markers, use only standard PEP 508 operators.
- Catch UndefinedComparison when evaluating markers from untrusted metadata.
- Keep the `packaging` library updated to match the marker syntax you depend on.
When it happens
Trigger: A Marker expression is evaluated whose AST contains an Op that serializes to a string not in _operators (which covers in, not in, <, <=, ==, !=, >=, >) and not parseable as a specifier prefix (==, !=, <=, >=, <, >, ~=). This generally means the marker was parsed from malformed or non-standard PEP 508 text.
Common situations: A third-party package's METADATA contains a malformed environment marker with a typo'd or non-standard operator. A packaging library version mismatch where a newer marker syntax is fed to an older parser. Programmatically constructing an invalid marker expression.
Related errors
- unable to parse identification
- invalid magic: {magic!r}
- unrecognized capacity ({self.capacity}) or encoding ({self.e
- unable to parse machine and section information
- duplicate labels in project urls
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/f9ec9a0e8686063b.
Report an issue: GitHub.