diff --git a/docs/docs/settings/error_codes.md b/docs/docs/settings/error_codes.md index e444125fdc26..bfd72f93990b 100644 --- a/docs/docs/settings/error_codes.md +++ b/docs/docs/settings/error_codes.md @@ -110,6 +110,14 @@ While using [invoke](../start/invoke.md), this can be overridden with the `--res An error occurred while rendering a component in the frontend. Typically this is caused by a browser caching issue, and can be resolved by clearing the browser cache and refreshing the page. If the issue persists, check the browser console for more information about the error. +#### INVE-E18 + +**Top Level Domain Required** + +The InvenTree server failed to start, because the configured server URL does not include a top-level domain (TLD). A valid TLD is required for proper operation. + +## Warning Codes + ### INVE-W (InvenTree Warning) Warnings - These are non-critical errors which should be addressed when possible. diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index cb691c2685a9..fe85764553cd 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -28,6 +28,7 @@ from InvenTree.config import get_boolean_setting, get_oidc_private_key, get_setting from InvenTree.ready import isInMainThread, isRunningBackup from InvenTree.sentry import default_sentry_dsn, init_sentry +from InvenTree.validators import invalid_site_url_hint from InvenTree.version import checkMinPythonVersion, inventreeCommitHash from users.oauth2_scopes import oauth2_scopes @@ -771,7 +772,7 @@ validator = URLValidator() validator(SITE_URL) except Exception: - msg = f"Invalid SITE_URL value: '{SITE_URL}'. InvenTree server cannot start." + msg = f"Invalid SITE_URL value: '{SITE_URL}'. InvenTree server cannot start.{invalid_site_url_hint(SITE_URL)}" logger.error(msg) print(msg) sys.exit(-1) diff --git a/src/backend/InvenTree/InvenTree/validators.py b/src/backend/InvenTree/InvenTree/validators.py index ae4145a140ae..13ab702e07a7 100644 --- a/src/backend/InvenTree/InvenTree/validators.py +++ b/src/backend/InvenTree/InvenTree/validators.py @@ -1,6 +1,8 @@ """Custom field validators for InvenTree.""" +import ipaddress import tokenize +from urllib.parse import urlsplit from django.conf import settings from django.core import validators @@ -88,6 +90,39 @@ def __call__(self, value): super().__call__(value) +def invalid_site_url_hint(site_url: str) -> str: + """Return an extra hint for *why* a SITE_URL value failed validation. + + Django's URLValidator rejects any hostname that isn't 'localhost', an IP + address, or a fully qualified (dotted) name - so a bare LAN hostname like + 'warehouse' fails with no indication of what's actually wrong. Returns an + empty string when nothing more specific than "invalid URL" applies. + """ + hostname = urlsplit(site_url).hostname + + if hostname is None and '//' not in site_url: + # No scheme was given at all, e.g. SITE_URL=warehouse + hostname = urlsplit(f'//{site_url}').hostname + + if not hostname or hostname == 'localhost': + return '' + + try: + ipaddress.ip_address(hostname) + return '' + except ValueError: + pass + + if '.' not in hostname: + return ( + f"INVE-E17: Top Level Domain Required.\ni'{hostname}' has no top-level domain. InvenTree requires a fully " + "qualified hostname (e.g. 'warehouse.local'), an IP address, or " + "'localhost' - a bare hostname is rejected by Django's URL validator." + ) + + return '' + + def validate_purchase_order_reference(value): """Validate the 'reference' field of a PurchaseOrder.""" from order.models import PurchaseOrder