{"id":"d034c26c12a619fc","repo":"pypa/pip","slug":"codepoint-unot-cp-value-at-position-pos-1","errorCode":null,"errorMessage":"Codepoint {_unot(cp_value)} at position {pos + 1} of {label!r} not allowed","messagePattern":"Codepoint (.+?) at position (.+?) of (.+?) not allowed","errorType":"validation","errorClass":"InvalidCodepoint","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":372,"sourceCode":"    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.\n    \"\"\"\n    if len(label) > _max_input_length:","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L354-L390","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nidna.encode('_acme-challenge.example.com')  # underscore is DISALLOWED\n\n// after\n# validate/strip non-LDH characters first, or handle the SRV-style label separately\nhost = '_acme-challenge.example.com'\nif host.startswith('_'):\n    # SRV / ACME records are not idna-encodable; pass through as-is\n    encoded = host.encode('ascii')\nelse:\n    encoded = idna.encode(host)","handlingStrategy":"validation","validationCode":"import idna, re\n\nLDH_RE = re.compile(r'^[A-Za-z0-9-]+$')\n\ndef is_dns_safe_label(label: str) -> bool:\n    # quick LDH (Letters-Digits-Hyphen) gate; idna.check_label is the full check\n    if not label or len(label) > 63:\n        return False\n    if label.startswith('-') or label.endswith('-'):\n        return False\n    if not LDH_RE.match(label):\n        # non-ASCII allowed only via idna; defer to check_label\n        try:\n            idna.check_label(label)\n        except idna.IDNAError:\n            return False\n    return True","typeGuard":"def is_ascii_ldh(s) -> bool:\n    return isinstance(s, str) and bool(s) and all(\n        'a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9' or c == '-' for c in s\n    )","tryCatchPattern":"import idna\n\ntry:\n    encoded = idna.encode(domain)\nexcept idna.InvalidCodepoint as err:\n    # disallowed/unassigned codepoint; reject the input\n    raise ValueError(f'invalid domain {domain!r}: {err}') from err","preventionTips":["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."],"tags":["idna","domain","unicode","codepoint","input-validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}