{"id":633,"library":"fqdn","title":"FQDN Validation Library","description":"The `fqdn` Python library, currently at version 1.5.1, provides RFC-compliant validation and manipulation of Fully Qualified Domain Names (FQDNs). Its primary purpose is to ensure that domain names adhere to Internet Engineering Task Force specifications like RFC 1123, making them suitable for traditional internet hostname usage. This is often a stricter subset of what modern web browsers accept. The library typically sees updates in response to specification clarifications or bug fixes, though major releases are infrequent.","status":"active","version":"1.5.1","language":"python","source_language":"en","source_url":"https://github.com/ypcrts/fqdn","tags":["fqdn","domain","validation","hostname","rfc","network"],"install":[{"cmd":"pip install fqdn","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Runtime environment","package":"python","optional":false}],"imports":[{"note":"The primary class for FQDN validation is `FQDN`.","wrong":"import fqdn","symbol":"FQDN","correct":"from fqdn import FQDN"}],"quickstart":{"code":"from fqdn import FQDN\n\ndomain_name_valid = 'example.com'\ndomain_name_invalid = 'localhost'\n\nfqdn_obj_valid = FQDN(domain_name_valid)\nfqdn_obj_invalid = FQDN(domain_name_invalid)\n\nprint(f\"'{domain_name_valid}' is valid: {fqdn_obj_valid.is_valid}\")\nprint(f\"Absolute form: {fqdn_obj_valid.absolute}\")\nprint(f\"'{domain_name_invalid}' is valid: {fqdn_obj_invalid.is_valid}\")\n\n# Example with relaxed constraints (though specific params aren't directly exposed in quickstart)\n# fqdn_obj_relaxed = FQDN('example', allow_single_label=True) # Illustrative, actual param might differ or be via a different method\n# print(f\"'example' is valid (relaxed): {fqdn_obj_relaxed.is_valid}\")","lang":"python","description":"Instantiate the `FQDN` class with a domain string and use its `is_valid` property to check for RFC compliance. Other properties like `absolute` and `relative` provide different representations."},"warnings":[{"fix":"Understand that `fqdn` prioritizes strict RFC compliance. If browser-like permissiveness is needed, custom relaxation of rules or an alternative library may be required.","message":"The `fqdn` library validates against strict RFC standards (e.g., RFC 1123, 1035), which are often more restrictive than what modern web browsers or certain Certificate Authorities (like Let's Encrypt) might accept as a valid domain name. This can lead to domains that work in browsers being rejected by `fqdn`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"If single-label hostnames or other non-standard formats are expected, consult the library's source or documentation for configuration options to relax specific constraints.","message":"By default, the `fqdn` library requires FQDNs to have a minimum of two labels (e.g., 'example.com' is valid, but 'example' is not). This is an explicit default constraint enabled to prevent breaking backwards compatibility with earlier versions.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use `from fqdn import FQDN` for external string validation. Use `import socket; socket.getfqdn()` only when inquiring about the local system's hostname resolution.","message":"Do not confuse this library (`fqdn`) with Python's built-in `socket.getfqdn()`. The `fqdn` library is designed for *validating arbitrary string inputs* as FQDNs, whereas `socket.getfqdn()` is used for *retrieving the Fully Qualified Domain Name of the local machine*.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For validation against actual registrable domains or live existence, combine `fqdn` with other libraries that perform DNS lookups (e.g., `dnspython`) or consult public suffix lists (e.g., `fqdn-parser`).","message":"The `fqdn` library primarily validates the *syntactic structure* of an FQDN according to RFCs. It does not perform live DNS lookups or validate against dynamic lists like IANA TLDs or the Public Suffix List. Therefore, a syntactically valid FQDN might not correspond to a *registrable* or *existing* domain on the internet.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T17:01:56.873Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install fqdn`","cause":"The `fqdn` library has not been installed in your Python environment.","error":"ModuleNotFoundError: No module named 'fqdn'"},{"fix":"To allow underscores, you need to instantiate `FQDN` with the `allow_underscore` parameter set to `True`: `from fqdn import FQDN; domain = FQDN('my_host.example.com', allow_underscore=True); print(domain.is_valid)`","cause":"The `fqdn` library, by default, enforces strict RFC compliance (e.g., RFC 1123) for FQDNs, which prohibits underscores in domain labels.","error":"fqdn.FQDN validation fails for domain with underscore"},{"fix":"To allow short hostnames (single-label or without a TLD), instantiate `FQDN` with the `allow_cached_without_dot` or `allow_non_canonical` (for broader relaxations) parameters set to `True`: `from fqdn import FQDN; domain = FQDN('localhost', allow_cached_without_dot=True); print(domain.is_valid)`","cause":"The `fqdn` library, adhering to RFCs, requires a fully qualified domain name with at least two labels (e.g., 'hostname.domain.com'). A single-label hostname or a hostname without a top-level domain (TLD) is considered invalid by default.","error":"fqdn.FQDN is_valid returns False for short hostname like 'localhost'"},{"fix":"Ensure the TLD of your domain name consists solely of alphabetic characters to comply with strict RFC standards. If numeric TLDs are needed for specific internal or non-standard uses, consider using the `allow_non_canonical` flag, but be aware this deviates from strict RFC compliance: `from fqdn import FQDN; domain = FQDN('example.123', allow_non_canonical=True); print(domain.is_valid)`","cause":"RFC specifications for FQDNs typically require the top-level domain (TLD) to contain only alphabetic characters, not numbers.","error":"fqdn.FQDN validation fails for numeric TLD (e.g., 'example.123')"}],"ecosystem":"pypi","meta_description":null,"install_score":80,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"1.5.1","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"17.8M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"17.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0,"mem_mb":0,"disk_size":"18M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"19.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"19.6M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0,"mem_mb":0,"disk_size":"20M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"11.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"11.5M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0,"mem_mb":0,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.2,"disk_size":"11.3M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.2,"disk_size":"11.2M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0,"mem_mb":0,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"17.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"17.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0,"mem_mb":0,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}