{"id":"c7ed94980d83b855","repo":"pypa/pip","slug":"codepoint-unot-cp-value-not-allowed-at-positio","errorCode":null,"errorMessage":"Codepoint {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}","messagePattern":"Codepoint (.+?) not allowed at position (.+?) in (.+?)","errorType":"validation","errorClass":"InvalidCodepointContext","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":370,"sourceCode":"    check_nfc(label)\n    check_hyphen_ok(label)\n    check_initial_combiner(label)\n\n    for pos, cp in enumerate(label):\n        cp_value = ord(cp)\n        if intranges_contain(cp_value, idnadata.codepoint_classes[\"PVALID\"]):\n            continue\n        if intranges_contain(cp_value, idnadata.codepoint_classes[\"CONTEXTJ\"]):\n            try:\n                if not valid_contextj(label, pos):\n                    raise InvalidCodepointContext(f\"Joiner {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}\")\n            except ValueError as err:\n                raise IDNAError(\n                    f\"Unknown codepoint adjacent to joiner {_unot(cp_value)} at position {pos + 1} in {label!r}\"\n                ) from err\n        elif intranges_contain(cp_value, idnadata.codepoint_classes[\"CONTEXTO\"]):\n            if not valid_contexto(label, pos):\n                raise InvalidCodepointContext(f\"Codepoint {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}\")\n        else:\n            raise InvalidCodepoint(f\"Codepoint {_unot(cp_value)} at position {pos + 1} of {label!r} not allowed\")\n\n    check_bidi(label)\n\n\ndef alabel(label: str) -> bytes:\n    \"\"\"Convert a single U-label into its A-label form.\n\n    The result is the ASCII-Compatible Encoding (ACE) form per :rfc:`5891`\n    §4: the label is validated, Punycode-encoded, and prefixed with\n    ``xn--``. Pure ASCII labels that are already valid IDNA labels are\n    returned unchanged (as :class:`bytes`).\n\n    :param label: The label to convert, as a Unicode string.\n    :returns: The A-label as ASCII-encoded :class:`bytes`.\n    :raises IDNAError: If the label is invalid or the resulting A-label\n        exceeds 63 octets.","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L352-L388","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nidna.encode('exa·mple.com')  # middle dot not between two 'l'\n\n// after\nidna.encode('exa-mple.com')   # use ASCII hyphen\n# or satisfy the Catalan rule:\nidna.encode('pa·l·l.com')  # 'l·l' is valid CONTEXTO","handlingStrategy":"validation","validationCode":"import idna\n\ndef is_valid_idna_label(label: str) -> bool:\n    try:\n        idna.check_label(label)\n        return True\n    except idna.IDNAError:\n        return False\n\n# pre-check before encode/alabel\nif not is_valid_idna_label(label):\n    raise ValueError(f'label {label!r} fails IDNA validation')\nencoded = idna.alabel(label)","typeGuard":"def is_idna_label_safe(s) -> bool:\n    return isinstance(s, str) and len(s) <= 63 and not s.startswith('-') and not s.endswith('-')","tryCatchPattern":"import idna\n\ntry:\n    encoded = idna.encode(domain)\nexcept idna.InvalidCodepointContext as err:\n    # CONTEXTO codepoint in illegal context\n    raise ValueError(f'invalid domain {domain!r}: {err}') from err","preventionTips":["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."],"tags":["idna","domain","unicode","codepoint","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}