{"id":"3cd678ae356bc3b9","repo":"pypa/pip","slug":"domain-too-long","errorCode":null,"errorMessage":"Domain too long","messagePattern":"Domain too long","errorType":"validation","errorClass":"IDNAError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":475,"sourceCode":"    Implements the mapping table from `UTS #46 §4\n    <https://www.unicode.org/reports/tr46/>`_: each character is kept,\n    replaced, or rejected based on its status (``V``, ``M``, ``D``, ``3``,\n    ``I``). The result is returned in Normalisation Form C.\n\n    :param domain: The full domain name to remap.\n    :param std3_rules: If ``True``, apply the stricter STD3 ASCII rules\n        (status ``3`` codepoints raise instead of being kept or mapped).\n    :param transitional: If ``True``, use transitional processing (status\n        ``D`` codepoints are mapped instead of kept). Transitional\n        processing has been removed from UTS #46 and this option is\n        retained only for backwards compatibility.\n    :returns: The remapped domain, in Normalisation Form C.\n    :raises InvalidCodepoint: If the domain contains a disallowed\n        codepoint under the chosen rules.\n    :raises IDNAError: If ``domain`` exceeds the defensive input length limit.\n    \"\"\"\n    if len(domain) > _max_input_length:\n        raise IDNAError(\"Domain too long\")\n    from .uts46data import uts46_replacements, uts46_starts, uts46_statuses\n\n    output = \"\"\n\n    for pos, char in enumerate(domain):\n        code_point = ord(char)\n        i = code_point if code_point < 256 else bisect.bisect_right(uts46_starts, code_point) - 1\n        status = chr(uts46_statuses[i])\n        replacement: Optional[str] = uts46_replacements[i]\n\n        # UTS #46 §4: V is always valid, D is deviation (kept unless transitional),\n        # 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 (","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L457-L493","documentation":"Raised by uts46_remap() (core.py:475) as a defensive guard when the input domain is longer than _max_input_length (1024 characters) before the per-codepoint UTS #46 mapping loop. This bounds work on oversized input; the real 253/254-octet DNS limit is enforced separately in encode()/decode() via valid_string_length().","triggerScenarios":"Calling uts46_remap() directly, or calling encode()/decode() with uts46=True, on a domain string longer than 1024 characters — typically a non-domain string (URL, token, log line) routed into the mapping function.","commonSituations":"Passing a full URL instead of a bare hostname to idna, a proxy feeding the whole request line into the IDNA path, fuzz tests with unbounded lengths, or concatenated domains missing separators.","solutions":["Extract the hostname component (e.g. via urllib.parse.urlsplit(s).hostname) before passing it to idna.","Reject inputs longer than 254 characters at the trust boundary — no valid domain is longer.","Cap input length to 1024 (or better, 254) and validate before calling uts46_remap/encode/decode."],"exampleFix":"// before\nidna.encode(long_url, uts46=True)  # full URL > 1024 chars\n\n// after\nfrom urllib.parse import urlsplit\nhost = urlsplit(long_url).hostname or long_url\nif len(host) > 253:\n    raise ValueError('hostname too long')\nidna.encode(host, uts46=True)","handlingStrategy":"validation","validationCode":"def is_acceptable_domain_length(domain: str, limit=254) -> bool:\n    return isinstance(domain, str) and len(domain) <= limit\n\nif not is_acceptable_domain_length(domain):\n    raise ValueError('domain too long for UTS #46 processing')\nremapped = idna.uts46_remap(domain)","typeGuard":"def is_bounded_str(s, limit=254) -> bool:\n    return isinstance(s, str) and len(s) <= limit","tryCatchPattern":"import idna\n\ntry:\n    encoded = idna.encode(domain, uts46=True)\nexcept idna.IDNAError as err:\n    if 'too long' in str(err):\n        raise ValueError('input exceeds domain length limits') from err\n    raise","preventionTips":["Extract the bare hostname (urlsplit(s).hostname) before passing to idna.","Enforce a 254-char cap on domain inputs at the trust boundary.","Never pass full URLs, tokens, or request lines into the UTS #46 / encode path."],"tags":["idna","domain","length","input-validation","dos-guard"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}