{"record":{"id":"f9ec9a0e8686063b","repo":"nodejs/node","slug":"undefined-op-r-on-lhs-r-and-rhs-r","errorCode":null,"errorMessage":"Undefined {op!r} on {lhs!r} and {rhs!r}.","messagePattern":"Undefined (.+?) on (.+?) and (.+?)\\.","errorType":"exception","errorClass":"UndefinedComparison","httpStatus":null,"severity":"error","filePath":"tools/gyp/pylib/packaging/markers.py","lineNumber":120,"sourceCode":"    \"<=\": operator.le,\n    \"==\": operator.eq,\n    \"!=\": operator.ne,\n    \">=\": operator.ge,\n    \">\": operator.gt,\n}\n\n\ndef _eval_op(lhs: str, op: Op, rhs: str) -> bool:\n    try:\n        spec = Specifier(\"\".join([op.serialize(), rhs]))\n    except InvalidSpecifier:\n        pass\n    else:\n        return spec.contains(lhs, prereleases=True)\n\n    oper: Optional[Operator] = _operators.get(op.serialize())\n    if oper is None:\n        raise UndefinedComparison(f\"Undefined {op!r} on {lhs!r} and {rhs!r}.\")\n\n    return oper(lhs, rhs)\n\n\ndef _normalize(*values: str, key: str) -> Tuple[str, ...]:\n    # PEP 685 – Comparison of extra names for optional distribution dependencies\n    # https://peps.python.org/pep-0685/\n    # > When comparing extra names, tools MUST normalize the names being\n    # > compared using the semantics outlined in PEP 503 for names\n    if key == \"extra\":\n        return tuple(canonicalize_name(v) for v in values)\n\n    # other environment markers don't have such standards\n    return values\n\n\ndef _evaluate_markers(markers: MarkerList, environment: Dict[str, str]) -> bool:\n    groups: List[List[bool]] = [[]]","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/gyp/pylib/packaging/markers.py#L102-L138","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (malformed marker in metadata)\nos_name ~=='posix'\n# after\nos_name == 'posix'","handlingStrategy":"try-catch","validationCode":"# Validate marker operators before evaluation\nfrom packaging.markers import Marker\n_VALID_OPS = {'==', '!=', '<=', '>=', '<', '>', '~=', 'in', 'not in'}\n# If constructing markers programmatically, ensure ops are in _VALID_OPS","typeGuard":"def is_valid_marker(text: str) -> bool:\n    from packaging.markers import Marker, InvalidMarker\n    try:\n        Marker(text)\n        return True\n    except InvalidMarker:\n        return False","tryCatchPattern":"from packaging.markers import UndefinedComparison\ntry:\n    result = Marker(text).evaluate()\nexcept UndefinedComparison as e:\n    print(f'unsupported operator in marker: {e}')\n    result = True  # safe default","preventionTips":["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."],"tags":["packaging","pep508","markers","environment-markers"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}