{"record":{"id":"551fb2a19df735d2","repo":"pypa/pip","slug":"unknown-license-exception-token-r","errorCode":null,"errorMessage":"Unknown license exception: {token!r}","messagePattern":"Unknown license exception: (.+?)","errorType":"validation","errorClass":"InvalidLicenseExpression","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/licenses/__init__.py","lineNumber":168,"sourceCode":"    normalized_tokens = []\n    last_license_start = False\n    for index, token in enumerate(tokens):\n        if token in {\"or\", \"and\", \"with\", \"(\", \")\"}:\n            if token == \"with\" and (\n                not last_license_start\n                or index + 1 == len(tokens)\n                or tokens[index + 1] in {\"or\", \"and\", \"with\", \"(\", \")\"}\n            ):\n                message = f\"Invalid license expression: {raw_license_expression!r}\"\n                raise InvalidLicenseExpression(message)\n            normalized_tokens.append(token.upper())\n            last_license_start = False\n            continue\n\n        if normalized_tokens and normalized_tokens[-1] == \"WITH\":\n            if token not in EXCEPTIONS:\n                message = f\"Unknown license exception: {token!r}\"\n                raise InvalidLicenseExpression(message)\n\n            normalized_tokens.append(EXCEPTIONS[token][\"id\"])\n            last_license_start = False\n        else:\n            if token.endswith(\"+\"):\n                final_token = token[:-1]\n                suffix = \"+\"\n            else:\n                final_token = token\n                suffix = \"\"\n\n            if final_token.startswith(\"licenseref-\"):\n                license_ref_id = final_token[len(\"licenseref-\") :]\n                if suffix or not license_ref_allowed.match(license_ref_id):\n                    message = f\"Invalid licenseref: {token!r}\"\n                    raise InvalidLicenseExpression(message)\n                normalized_tokens.append(license_refs[final_token])\n            else:","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/licenses/__init__.py#L150-L186","documentation":"Raised during the final token pass of canonicalize_license_expression (licenses/__init__.py:167-168). When the previous normalized token is WITH, the current token is looked up in the SPDX EXCEPTIONS table; if it is not a registered SPDX license-exception identifier, InvalidLicenseExpression is raised. The input is lowercased first, so casing of the identifier does not matter, but the spelling must match an SPDX-listed exception.","triggerScenarios":"Passing 'mit with foo' (foo not an exception), 'apache-2.0 with linux-syscall' (correct id is 'Linux-syscall-note'), or 'mit with apache-2.0' (a license id used where an exception id belongs).","commonSituations":"Guessing or abbreviating exception identifiers; using a license id after WITH; an older packaging vendoring an older SPDX list that lacks a newer exception id.","solutions":["Use the exact SPDX exception identifier, e.g. 'Classpath-exception-2.0', 'LLVM-exception', 'Linux-syscall-note'.","Remove the WITH clause if you are unsure which exception applies."],"exampleFix":"# before\ncanonicalize_license_expression('mit with linux-syscall')\n# after\ncanonicalize_license_expression('apache-2.0 with linux-syscall-note')","handlingStrategy":"try-catch","validationCode":"from pip._vendor.packaging.licenses._spdx import EXCEPTIONS\n\ndef is_known_exception(token: str) -> bool:\n    return token.lower() in EXCEPTIONS\n","typeGuard":null,"tryCatchPattern":"from packaging.licenses import canonicalize_license_expression, InvalidLicenseExpression\n\ntry:\n    canonicalize_license_expression(expr)\nexcept InvalidLicenseExpression as e:\n    # surface to user / config validation\n    ...\n","preventionTips":["Keep a reference to the SPDX exceptions list when building license UIs.","Treat WITH's right operand as an exception id, not a license id."],"tags":["spdx","license","validation","packaging"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}