{"id":"7bfe53c604a77602","repo":"pypa/pip","slug":"codepoint-unot-code-point-not-allowed-at-posit","errorCode":null,"errorMessage":"Codepoint {_unot(code_point)} not allowed at position {pos + 1} in {domain!r}","messagePattern":"Codepoint (.+?) not allowed at position (.+?) in (.+?)","errorType":"validation","errorClass":"InvalidCodepoint","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":505,"sourceCode":"        # 3 is disallowed-STD3 (kept unmapped if std3_rules is off and no mapping).\n        keep_as_is = (\n            status == \"V\" or (status == \"D\" and not transitional) or (status == \"3\" and not std3_rules and replacement is None)\n        )\n        # M is mapped, 3-with-replacement and transitional D fall through to the\n        # same replacement output path.\n        use_replacement = replacement is not None and (\n            status == \"M\" or (status == \"3\" and not std3_rules) or (status == \"D\" and transitional)\n        )\n\n        if keep_as_is:\n            output += char\n        elif use_replacement:\n            assert replacement is not None  # narrowed by use_replacement\n            output += replacement\n        elif status == \"I\":\n            continue\n        else:\n            raise InvalidCodepoint(f\"Codepoint {_unot(code_point)} not allowed at position {pos + 1} in {domain!r}\")\n\n    return unicodedata.normalize(\"NFC\", output)\n\n\ndef encode(\n    s: Union[str, bytes, bytearray],\n    strict: bool = False,\n    uts46: bool = False,\n    std3_rules: bool = False,\n    transitional: bool = False,\n) -> bytes:\n    \"\"\"Encode a Unicode domain name into its ASCII (A-label) form.\n\n    Splits the input on label separators (only ``U+002E`` if ``strict`` is\n    set; otherwise also IDEOGRAPHIC FULL STOP ``U+3002``, FULLWIDTH FULL\n    STOP ``U+FF0E``, and HALFWIDTH IDEOGRAPHIC FULL STOP ``U+FF61``),\n    encodes each label with :func:`alabel`, and rejoins them with ``.``.\n    Optionally pre-processes the input through :func:`uts46_remap`.","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L487-L523","documentation":"Raised by uts46_remap() (core.py:505) when a codepoint's UTS #46 status is not V (valid), D (deviation), 3 (disallowed-STD3), or I (ignored) — i.e. it is outright disallowed under UTS #46 and std3/transition handling does not rescue it. The exception class is InvalidCodepoint and the message names the codepoint (U+XXXX) and its position. This is the UTS #46 counterpart of the IDNA 2008 disallowed-codepoint error (261), reached when uts46=True is used.","triggerScenarios":"Calling uts46_remap() directly, or encode()/decode() with uts46=True, on a domain containing a codepoint UTS #46 marks disallowed — control characters, most symbols/punctuation, emoji, or private-use codepoints. With std3_rules=True (default for uts46_remap) additional ASCII punctuation like '_' also falls here when no mapping is defined.","commonSituations":"Emoji or symbol hostnames, underscores in uts46=True mode, copy-pasted domains with invisible control/format characters, private-use or unassigned codepoints, or input from systems that did no Unicode normalisation.","solutions":["Remove or replace the reported codepoint (U+XXXX) with an LDH-safe character before encoding.","Call uts46_remap(domain, std3_rules=False) to relax the STD3 rules so more ASCII punctuation is tolerated, if your use case allows it.","Sanitise the domain at the input boundary: NFC-normalise, strip control/format categories, and restrict to an allow-list before handing to idna."],"exampleFix":"// before\nidna.encode('a_b.example', uts46=True, std3_rules=True)  # '_' disallowed\n\n// after\nidna.encode('a_b.example', uts46=True, std3_rules=False)  # tolerate '_'\n# or strip non-LDH first:\nimport unicodedata\nclean = ''.join(c for c in domain if unicodedata.category(c)[0] not in ('C','Z'))\nidna.encode(clean, uts46=True)","handlingStrategy":"validation","validationCode":"import idna\n\ndef uts46_safe(domain: str, std3_rules: bool = False) -> str:\n    try:\n        return idna.uts46_remap(domain, std3_rules=std3_rules)\n    except idna.InvalidCodepoint:\n        raise ValueError(f'domain {domain!r} contains a UTS #46-disallowed codepoint')\n\nremapped = uts46_safe(domain, std3_rules=False)","typeGuard":"import unicodedata\n\ndef is_uts46_plausible(s) -> bool:\n    if not isinstance(s, str):\n        return False\n    return all(unicodedata.category(c)[0] not in ('C', 'Z', 'M') for c in s)","tryCatchPattern":"import idna\n\ntry:\n    encoded = idna.encode(domain, uts46=True)\nexcept idna.InvalidCodepoint as err:\n    raise ValueError(f'invalid domain {domain!r}: {err}') from err","preventionTips":["NFC-normalise and strip control/format/whitespace categories before encoding.","Use std3_rules=False in uts46_remap/encode when you need to tolerate ASCII punctuation like '_'.","Keep vendored idna/Python current so the UTS #46 tables match modern input."],"tags":["idna","domain","unicode","codepoint","uts46"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}