pypa/pip · error · InvalidCodepoint
Codepoint {_unot(cp_value)} at position {pos + 1} of {label!
Error message
Codepoint {_unot(cp_value)} at position {pos + 1} of {label!r} not allowed What it means
Raised by check_label (core.py:372) when a codepoint is neither PVALID, CONTEXTJ, nor CONTEXTO — i.e. it is DISALLOWED or UNASSIGNED under IDNA 2008 (RFC 5892). The codepoint is rejected outright regardless of context; the exception class is InvalidCodepoint and the message reports the codepoint as U+XXXX and its position. This is the catch-all for characters the IDNA tables simply do not permit in a label.
Source
Thrown at src/pip/_vendor/idna/core.py:372
check_initial_combiner(label)
for pos, cp in enumerate(label):
cp_value = ord(cp)
if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]):
continue
if intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]):
try:
if not valid_contextj(label, pos):
raise InvalidCodepointContext(f"Joiner {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}")
except ValueError as err:
raise IDNAError(
f"Unknown codepoint adjacent to joiner {_unot(cp_value)} at position {pos + 1} in {label!r}"
) from err
elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]):
if not valid_contexto(label, pos):
raise InvalidCodepointContext(f"Codepoint {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}")
else:
raise InvalidCodepoint(f"Codepoint {_unot(cp_value)} at position {pos + 1} of {label!r} not allowed")
check_bidi(label)
def alabel(label: str) -> bytes:
"""Convert a single U-label into its A-label form.
The result is the ASCII-Compatible Encoding (ACE) form per :rfc:`5891`
§4: the label is validated, Punycode-encoded, and prefixed with
``xn--``. Pure ASCII labels that are already valid IDNA labels are
returned unchanged (as :class:`bytes`).
:param label: The label to convert, as a Unicode string.
:returns: The A-label as ASCII-encoded :class:`bytes`.
:raises IDNAError: If the label is invalid or the resulting A-label
exceeds 63 octets.
"""
if len(label) > _max_input_length:View on GitHub (pinned to d7d0d0a394)
Solutions
- Strip or replace the reported codepoint (the U+XXXX in the message) — most often an underscore, wildcard, emoji, or invisible format character — before encoding.
- Validate domains against a DNS-safe charset (RFC 1035 LDH: letters, digits, hyphen) before passing them to idna; reject or normalise anything else upstream.
- If you genuinely need permissive Unicode handling, call encode(domain, uts46=True, std3_rules=False) so UTS #46 mapping tolerates more input, or upgrade the idna/Python version to refresh the Unicode tables for recently-assigned codepoints.
Example fix
// before
idna.encode('_acme-challenge.example.com') # underscore is DISALLOWED
// after
# validate/strip non-LDH characters first, or handle the SRV-style label separately
host = '_acme-challenge.example.com'
if host.startswith('_'):
# SRV / ACME records are not idna-encodable; pass through as-is
encoded = host.encode('ascii')
else:
encoded = idna.encode(host) Defensive patterns
Strategy: validation
Validate before calling
import idna, re
LDH_RE = re.compile(r'^[A-Za-z0-9-]+$')
def is_dns_safe_label(label: str) -> bool:
# quick LDH (Letters-Digits-Hyphen) gate; idna.check_label is the full check
if not label or len(label) > 63:
return False
if label.startswith('-') or label.endswith('-'):
return False
if not LDH_RE.match(label):
# non-ASCII allowed only via idna; defer to check_label
try:
idna.check_label(label)
except idna.IDNAError:
return False
return True Type guard
def is_ascii_ldh(s) -> bool:
return isinstance(s, str) and bool(s) and all(
'a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9' or c == '-' for c in s
) Try / catch
import idna
try:
encoded = idna.encode(domain)
except idna.InvalidCodepoint as err:
# disallowed/unassigned codepoint; reject the input
raise ValueError(f'invalid domain {domain!r}: {err}') from err Prevention
- Reject underscores, wildcards, and emoji in hostname fields before they reach idna.
- NFC-normalise input and strip zero-width / format characters before encoding.
- Upgrade idna (and Python) to refresh Unicode tables when hitting unassigned-codepoint errors.
When it happens
Trigger: Calling idna.encode(), idna.alabel(), or idna.check_label() on a label containing a disallowed or unassigned character: control characters, symbols such as underscore in the wrong position, emoji, currency signs, punctuation outside the allowed set, or a codepoint allocated in a newer Unicode version than the vendored idnadata tables know about.
Common situations: Config/host files containing underscores or wildcards ('_acme-challenge', '*.'), copy-pasted domains containing invisible formatting characters (BOM, zero-width spaces), emoji subdomains, emoji in email/HTTP Host headers reaching an idna encode path, or running an older idna release against input using recently-assigned Unicode scripts.
Related errors
- Codepoint {_unot(cp_value)} not allowed at position {pos + 1
- Codepoint {_unot(code_point)} not allowed at position {pos +
- Domain too long
- Empty domain
- Empty label
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/d034c26c12a619fc.json.
Report an issue: GitHub.