pypa/pip · error · InvalidLicenseExpression
Unknown license
Error message
Unknown license: {final_token!r} What it means
Raised during the final pass of canonicalize_license_expression (licenses/__init__.py:187-189). Any token that is not a boolean op, paren, WITH, or a LicenseRef-* must be a recognized SPDX license identifier present in the LICENSES table; otherwise InvalidLicenseExpression is raised. The token is lowercased before lookup, so only the exact SPDX spelling (case-insensitive) is accepted.
Solutions
- Use the exact SPDX license identifier (e.g. 'MIT', 'Apache-2.0', 'BSD-3-Clause', 'GPL-3.0-or-later').
- For non-SPDX licenses, use a 'LicenseRef-*' token instead.
Example fix
# before
canonicalize_license_expression('GPLv3')
# after
canonicalize_license_expression('GPL-3.0-or-later') Defensive patterns
Strategy: try-catch
Validate before calling
from pip._vendor.packaging.licenses._spdx import LICENSES
def is_known_license(token: str) -> bool:
t = token.lower().removesuffix("+")
return t.startswith("licenseref-") or t in LICENSES
Try / catch
from packaging.licenses import canonicalize_license_expression, InvalidLicenseExpression
try:
canonicalize_license_expression(expr)
except InvalidLicenseExpression as e:
...
Prevention
- Use canonical SPDX license ids (MIT, Apache-2.0, BSD-3-Clause, GPL-3.0-or-later).
- Use LicenseRef-* for non-SPDX licenses.
When it happens
Trigger: Passing 'Use-it-after-midnight', 'proprietary', 'BSD' (too vague — use 'BSD-3-Clause'), 'GPLv3' (use 'GPL-3.0-only'/'GPL-3.0-or-later'), or 'Apache' (use 'Apache-2.0').
Common situations: Using colloquial or display license names; forgetting the -only/-or-later suffix on GPL family licenses; a newer SPDX id absent from an older vendored packaging; custom licenses not written as LicenseRef-*.
Related errors
- Invalid license expression
- Invalid licenseref
- Unknown license exception
- Compressed tag set would generate
- Invalid sdist filename
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/7db903a5760f592e.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/packaging/licenses/__init__.py:189
last_license_start = False
else:
if token.endswith("+"):
final_token = token[:-1]
suffix = "+"
else:
final_token = token
suffix = ""
if final_token.startswith("licenseref-"):
license_ref_id = final_token[len("licenseref-") :]
if suffix or not license_ref_allowed.match(license_ref_id):
message = f"Invalid licenseref: {token!r}"
raise InvalidLicenseExpression(message)
normalized_tokens.append(license_refs[final_token])
else:
if final_token not in LICENSES:
message = f"Unknown license: {final_token!r}"
raise InvalidLicenseExpression(message)
normalized_tokens.append(LICENSES[final_token]["id"] + suffix)
last_license_start = True
normalized_expression = " ".join(normalized_tokens)
return cast(
"NormalizedLicenseExpression",
normalized_expression.replace("( ", "(").replace(" )", ")"),
)
View on GitHub (pinned to f399c37189)