pypa/pip · error · IDNAError
Empty domain
Error message
Empty domain
What it means
Raised by idna.encode and idna.decode when the input domain string is effectively empty — after splitting on label separators, labels is empty or equals ['']. This catches inputs like '', or strings consisting only of separator characters.
Solutions
- Check for empty or whitespace-only input before calling encode/decode.
- Treat empty hostname as a special case (e.g. use 'localhost' or reject the form).
- Validate the URL contains a non-empty hostname before extracting it for IDNA.
Example fix
# before
host = parsed.hostname or ''
idna.encode(host) # raises Empty domain when host is ''
# after
host = parsed.hostname
if not host:
raise ValueError('Hostname is required')
idna.encode(host) Defensive patterns
Strategy: validation
Validate before calling
def is_non_empty_domain(domain: str) -> bool:
return bool(domain and domain.strip()) Type guard
def is_non_empty_domain(domain: str) -> bool:
return isinstance(domain, str) and len(domain.strip()) > 0 Try / catch
from idna.core import IDNAError
try:
result = idna.encode(domain)
except IDNAError:
if not domain:
raise ValueError('Domain must not be empty')
raise Prevention
- Check for empty/None hostnames before IDNA encoding.
- Use URL parsing to validate hostname presence.
- Provide sensible defaults for missing hostnames.
When it happens
Trigger: Calling idna.encode('') or idna.decode(''), or passing a string of only dots such as '.' or '...' where all labels are stripped.
Common situations: Empty hostname field from a parsed URL; user form with blank domain; programmatic generation that produces empty strings; default/placeholder values passed through.
Related errors
- Domain too long
- Empty label
- Unsupported error handling
- At least one hash must be provided
- Cannot determine sdist filename
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/7b7d7da809ff268b.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_vendor/idna/core.py:630
"""
if not isinstance(s, str):
try:
s = str(s, "ascii")
except (UnicodeDecodeError, TypeError) as err:
raise IDNAError("Invalid ASCII in A-label") from err
if len(s) > _max_input_length:
raise IDNAError("Domain too long")
if uts46:
s = uts46_remap(s, std3_rules, False)
# 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 not labels[-1]:
del labels[-1]
trailing_dot = True
for label in labels:
try:
u = ulabel(label)
except IDNAError:
if display and label[:4].lower() == "xn--":
u = label.lower()
else:
raise
if u:
result.append(u)
else:
raise IDNAError("Empty label")
if trailing_dot:
result.append("")
return ".".join(result)View on GitHub (pinned to f399c37189)