pypa/pip · error · InvalidCodepointContext
Codepoint {_unot(cp_value)} not allowed at position {pos + 1
Error message
Codepoint {_unot(cp_value)} not allowed at position {pos + 1} in {label!r} What it means
Raised by check_label (core.py:370) during IDNA 2008 validation when a CONTEXTO-class codepoint appears in a context not permitted by RFC 5892 Appendix A. CONTEXTO codepoints (MIDDLE DOT U+00B7, Greek lower numeral sign U+0375, Hebrew geresh/gereshayim U+05F3/U+05F4, Katakana middle dot U+30FB, Arabic-Indic digits U+0660-0669, Extended Arabic-Indic digits U+06F0-06F9) are only legal alongside specific scripts or characters; if valid_contexto() returns False the label is rejected with InvalidCodepointContext. The message names the codepoint (U+XXXX) and its 1-based position so the offending character is identifiable.
Source
Thrown at src/pip/_vendor/idna/core.py:370
check_nfc(label)
check_hyphen_ok(label)
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.View on GitHub (pinned to d7d0d0a394)
Solutions
- Identify the codepoint from the U+XXXX token in the message and remove or replace it (typically with an ASCII hyphen or nothing) before calling encode().
- If the punctuation is intentional, restructure the surrounding characters to satisfy the rule, e.g. ensure a U+00B7 is flanked by 'l' on both sides, or drop the Arabic-Indic digit block that conflicts.
- Pre-process the domain with idna.uts46_remap(domain, std3_rules=False) or call encode(domain, uts46=True) so the UTS #46 mapping table normalises or rejects the character consistently.
Example fix
// before
idna.encode('exa·mple.com') # middle dot not between two 'l'
// after
idna.encode('exa-mple.com') # use ASCII hyphen
# or satisfy the Catalan rule:
idna.encode('pa·l·l.com') # 'l·l' is valid CONTEXTO Defensive patterns
Strategy: validation
Validate before calling
import idna
def is_valid_idna_label(label: str) -> bool:
try:
idna.check_label(label)
return True
except idna.IDNAError:
return False
# pre-check before encode/alabel
if not is_valid_idna_label(label):
raise ValueError(f'label {label!r} fails IDNA validation')
encoded = idna.alabel(label) Type guard
def is_idna_label_safe(s) -> bool:
return isinstance(s, str) and len(s) <= 63 and not s.startswith('-') and not s.endswith('-') Try / catch
import idna
try:
encoded = idna.encode(domain)
except idna.InvalidCodepointContext as err:
# CONTEXTO codepoint in illegal context
raise ValueError(f'invalid domain {domain!r}: {err}') from err Prevention
- Sanitise user-supplied hostnames with unicodedata category checks, rejecting format/control/surrogate codepoints before encoding.
- Run idna.uts46_remap(domain) first and surface remap failures as user-facing validation errors.
- In tests, include CONTEXTO fixtures (Catalan l·l, mixed Arabic digit blocks) to catch regressions.
When it happens
Trigger: Calling idna.encode(), idna.alabel(), or idna.check_label() with a Unicode label whose CONTEXTO codepoint fails its rule: a U+00B7 not sandwiched between two lowercase 'l' (Catalan l·l), a Katakana middle dot with no Hiragana/Katakana/Han character in the label, Arabic-Indic and Extended Arabic-Indic digits mixed in the same label, or a Hebrew U+05F3/U+05F4 not preceded by a Hebrew character.
Common situations: Hostnames pasted from word processors that substitute a real middle dot for a hyphen, transliterated/multilingual test fixtures mixing Latin punctuation with CJK or Arabic content, user-generated subdomains that accidentally include numeral-sign punctuation, and data migrated from systems using IDNA 2003 which did not enforce these contextual rules.
Related errors
- Codepoint {_unot(cp_value)} at position {pos + 1} of {label!
- Codepoint {_unot(code_point)} not allowed at position {pos +
- Label too long
- Unknown directionality in label {label!r} at position {idx}
- First codepoint in label {label!r} must be directionality L,
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/c7ed94980d83b855.json.
Report an issue: GitHub.