pypa/pip · error · IDNAError
Label has disallowed hyphens in 3rd and 4th position
Error message
Label has disallowed hyphens in 3rd and 4th position
What it means
IDNAError from check_hyphen_ok: per RFC 5891 §4.2.3.1 a label must not contain hyphens in both the 3rd and 4th positions (label[2:4] == '--'). That pattern is reserved as the prefix of ACE (Punycode) A-labels ('xn--'), and a U-label matching it would be ambiguous.
Source
Thrown at src/pip/_vendor/idna/core.py:201
"""
if unicodedata.category(label[0])[0] == "M":
raise IDNAError("Label begins with an illegal combining character")
return True
def check_hyphen_ok(label: str) -> bool:
"""Validate the hyphen restrictions for a label.
Per :rfc:`5891` §4.2.3.1 a label must not start or end with a hyphen
(``U+002D``), and must not have hyphens in both the third and fourth
positions (the prefix reserved for A-labels).
:param label: The label to check.
:returns: ``True`` if the hyphen restrictions are satisfied.
:raises IDNAError: If any of the hyphen restrictions are violated.
"""
if label[2:4] == "--":
raise IDNAError("Label has disallowed hyphens in 3rd and 4th position")
if label[0] == "-" or label[-1] == "-":
raise IDNAError("Label must not start or end with a hyphen")
return True
def check_nfc(label: str) -> None:
"""Require that a label is in Unicode Normalization Form C.
:param label: The label to check.
:raises IDNAError: If ``label`` differs from its NFC normalisation.
"""
if len(label) > _max_input_length:
raise IDNAError("Label too long")
if unicodedata.normalize("NFC", label) != label:
raise IDNAError("Label must be in Normalization Form C")
def valid_contextj(label: str, pos: int) -> bool:View on GitHub (pinned to d7d0d0a394)
Solutions
- Avoid placing '--' at positions 3-4; use a different separator or pad the prefix to 3+ characters before the hyphens.
- If the input is already an A-label (xn--...), pass it through ulabel/decode rather than re-encoding via alabel.
- Rename the label so the double hyphen appears elsewhere.
Example fix
# before
idna.encode('ab--العرب') # disallowed hyphens in 3rd and 4th position
# after
idna.encode('abc--العرب') # double hyphen no longer at 3-4 Defensive patterns
Strategy: validation
Validate before calling
def avoids_reserved_ace_prefix(label: str) -> bool:
return label[2:4] != '--' Type guard
def is_safe_label_for_ace(label: str) -> bool:
return len(label) < 4 or label[2:4] != '--' Try / catch
from idna import IDNAError
try:
idna.encode(label)
except IDNAError as e:
if '3rd and 4th' in str(e):
# relocate the double-hyphen away from positions 3-4
raise ValueError('reserved ACE prefix shape; rename label') from e
raise Prevention
- Do not place '--' at positions 3-4 of a U-label; that shape is reserved for xn-- A-labels.
- If the input is already an xn-- A-label, decode it via idna.decode rather than re-encoding.
- Use a separator other than '--' in generated names.
When it happens
Trigger: A non-ASCII U-label whose 3rd and 4th characters are both hyphens, e.g. 'ab--العرب'. Encountered when alabel/check_label processes a label that was not already an xn-- A-label but happens to match the reserved prefix shape.
Common situations: Auto-generated names of the form '<2chars>--<rest>'; user handles containing a double-hyphen after a short prefix; data from a system that uses '--' as a separator glued directly to a 2-char prefix.
Related errors
- Label must not start or end with a hyphen
- Label too long
- Label begins with an illegal combining character
- Label must be in Normalization Form C
- Empty Label
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/39ac96b5ef0d8943.json.
Report an issue: GitHub.