pypa/pip · error · IDNAError
Empty label
Error message
Empty label
What it means
Raised by encode() (core.py:573) inside the per-label loop when alabel() returns a falsy result for a non-empty-looking label — i.e. encoding produced an empty byte string. In practice this guards against a label that is empty after splitting (consecutive separators producing an empty segment not at the trailing position), which alabel treats as empty.
Source
Thrown at src/pip/_vendor/idna/core.py:573
# Reject inputs that exceed the maximum DNS domain length up-front
# to avoid expensive computation on long inputs.
if not valid_string_length(s, trailing_dot=True):
raise IDNAError("Domain too long")
trailing_dot = False
result = []
labels = s.split(".") if strict else _unicode_dots_re.split(s)
if not labels or labels == [""]:
raise IDNAError("Empty domain")
if labels[-1] == "":
del labels[-1]
trailing_dot = True
for label in labels:
s = alabel(label)
if s:
result.append(s)
else:
raise IDNAError("Empty label")
if trailing_dot:
result.append(b"")
s = b".".join(result)
if not valid_string_length(s, trailing_dot):
raise IDNAError("Domain too long")
return s
def decode(
s: Union[str, bytes, bytearray],
strict: bool = False,
uts46: bool = False,
std3_rules: bool = False,
display: bool = False,
) -> str:
"""Decode an A-label-encoded domain name back to Unicode.
Splits the input on label separators (see :func:`encode` for theView on GitHub (pinned to d7d0d0a394)
Solutions
- Normalise the domain by collapsing consecutive dots and stripping leading/trailing dots before encoding.
- Validate that every dot-separated segment is non-empty: all(labels) and all(l != '' for l in labels).
- Fix the templating/construction bug that produced the empty middle segment.
Example fix
// before
idna.encode(f'{a}.{middle}.{b}') # middle == '' -> 'a..b'
// after
labels = [l for l in domain.split('.') if l]
if not labels:
raise ValueError('empty domain')
idna.encode('.'.join(labels)) Defensive patterns
Strategy: validation
Validate before calling
def has_no_empty_labels(domain: str) -> bool:
labels = domain.split('.')
# allow a single trailing empty label (trailing dot)
if labels and labels[-1] == '':
labels = labels[:-1]
return bool(labels) and all(l != '' for l in labels)
if not has_no_empty_labels(domain):
raise ValueError(f'domain {domain!r} has empty labels (consecutive dots)')
encoded = idna.encode(domain) Type guard
def is_clean_domain(s) -> bool:
if not isinstance(s, str) or not s:
return False
return '..' not in s and not s.startswith('.') Try / catch
import idna
try:
encoded = idna.encode(domain)
except idna.IDNAError as err:
if 'Empty label' in str(err):
# collapse consecutive dots and retry
import re
cleaned = re.sub(r'\.+', '.', domain).strip('.')
encoded = idna.encode(cleaned)
else:
raise Prevention
- Normalise domains: collapse consecutive dots and strip leading/trailing dots before encoding.
- Validate every dot-separated segment is non-empty before encoding.
- Guard templating (f'{a}.{b}.{c}') against empty middle components.
When it happens
Trigger: Calling idna.encode() with a domain containing an internal empty label from consecutive separators, e.g. 'a..b.com', 'a...b.com', or a leading empty segment — anything where split yields '' between two real labels.
Common situations: User-typed domains with double dots, string-joining bugs that emit '..' between parts, templated hostnames with a missing middle component (f'{a}.{b}.{c}' where b is ''), or copy-paste artefacts.
Related errors
- Empty domain
- Codepoint {_unot(cp_value)} at position {pos + 1} of {label!
- Domain too long
- Codepoint {_unot(cp_value)} not allowed at position {pos + 1
- Malformed A-label, no Punycode eligible content found
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/48bc01cc13e178d4.json.
Report an issue: GitHub.