{"id":"7f0f6a797e2074ab","repo":"pypa/pip","slug":"label-begins-with-an-illegal-combining-character","errorCode":null,"errorMessage":"Label begins with an illegal combining character","messagePattern":"Label begins with an illegal combining character","errorType":"validation","errorClass":"IDNAError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/idna/core.py","lineNumber":185,"sourceCode":"\n    if not valid_ending:\n        raise IDNABidiError(\"Label ends with illegal codepoint directionality\")\n\n    return True\n\n\ndef check_initial_combiner(label: str) -> bool:\n    \"\"\"Reject labels that begin with a combining mark.\n\n    Per :rfc:`5891` §4.2.3.2 a label must not start with a character of\n    Unicode general category ``M`` (Mark).\n\n    :param label: The label to check.\n    :returns: ``True`` if the first character is not a combining mark.\n    :raises IDNAError: If the label begins with a combining character.\n    \"\"\"\n    if unicodedata.category(label[0])[0] == \"M\":\n        raise IDNAError(\"Label begins with an illegal combining character\")\n    return True\n\n\ndef check_hyphen_ok(label: str) -> bool:\n    \"\"\"Validate the hyphen restrictions for a label.\n\n    Per :rfc:`5891` §4.2.3.1 a label must not start or end with a hyphen\n    (``U+002D``), and must not have hyphens in both the third and fourth\n    positions (the prefix reserved for A-labels).\n\n    :param label: The label to check.\n    :returns: ``True`` if the hyphen restrictions are satisfied.\n    :raises IDNAError: If any of the hyphen restrictions are violated.\n    \"\"\"\n    if label[2:4] == \"--\":\n        raise IDNAError(\"Label has disallowed hyphens in 3rd and 4th position\")\n    if label[0] == \"-\" or label[-1] == \"-\":\n        raise IDNAError(\"Label must not start or end with a hyphen\")","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/idna/core.py#L167-L203","documentation":"IDNAError from check_initial_combiner: per RFC 5891 §4.2.3.2 a label must not begin with a character of Unicode general category M (Mark – Mn, Mc, Me). A leading combining mark has no base character to combine with and is rejected.","triggerScenarios":"A label whose first character is a combining mark, e.g. '́abc' (combining acute) or 'ًالعرب' (Arabic tanvin leading). check_initial_combiner is called from check_label during alabel/encode.","commonSituations":"Strings that lost their leading base character through truncation or normalization; concatenation that puts a combining mark at the start; copy-paste from sources that include leading diacritics; NFC normalization that did not collapse a detached mark.","solutions":["Ensure the first character of each label is a base character (letter/digit), not a combining mark.","Apply unicodedata.normalize('NFC', label) first so combining marks attach to a base.","Strip leading category-M characters: while unicodedata.category(label[0])[0]=='M': label=label[1:]."],"exampleFix":"# before\nidna.encode('́test')  # Label begins with illegal combining character\n\n# after\nidna.encode('test')\n# or pre-normalize:\nidna.encode(unicodedata.normalize('NFC', '́test'))  # if a base precedes it","handlingStrategy":"validation","validationCode":"import unicodedata\ndef strip_leading_combiners(label: str) -> str:\n    while label and unicodedata.category(label[0])[0] == 'M':\n        label = label[1:]\n    return label","typeGuard":"import unicodedata\ndef starts_with_base_char(label: str) -> bool:\n    return bool(label) and unicodedata.category(label[0])[0] != 'M'","tryCatchPattern":"from idna import IDNAError\ntry:\n    idna.encode(label)\nexcept IDNAError as e:\n    if 'combining character' in str(e):\n        label = strip_leading_combiners(label)  # or normalize NFC upstream\n    else:\n        raise","preventionTips":["Always NFC-normalize user input before IDNA: unicodedata.normalize('NFC', s).","Reject or strip leading category-M characters at the input boundary.","Validate that the first character is a base letter/digit."],"tags":["idna","unicode","normalization","rfc5891","pip"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}