langflow-ai/langflow · error · ValueError
webhook url has an invalid host: {exc}
Error message
webhook url has an invalid host: {exc} What it means
Raised by validate_webhook_url when httpx.URL rejects the webhook host as IDNA-invalid (httpx.InvalidURL), translated to ValueError because callers only guard ValueError. Without the translation an exotic/illegal hostname would escape as a 500 or crash the dispatch loop instead of failing closed as an unsafe webhook. It complements the urlparse check by validating the exact ASCII host httpx would connect to.
Source
Thrown at src/backend/base/langflow/api/v1/a2a_utils.py:132
# unicode urlparse hostname, so an IDN webhook is pinned/resolved by the exact ASCII host
# the connection uses (else the pin silently misses: TOCTOU rebind for IDN hosts). httpx.URL
# raises InvalidURL (not ValueError) for an IDNA-invalid host, so keep it inside the try.
host = webhook_pin_host(url)
# Hard floor: reject private/metadata IPs even when global SSRF protection is off
# (validate_and_resolve_url returns [] with NO enforcement in that case).
# resolve_hostname handles IP-literal hosts too; the blocking resolve runs off-loop.
floor_ips = await asyncio.to_thread(resolve_hostname, host)
blocked = [ip for ip in floor_ips if is_ip_blocked(ip)]
if blocked:
msg = f"webhook url resolves to a blocked address: {', '.join(blocked)}"
raise ValueError(msg)
# Then the framework check for allowlist / CGNAT / is_global extras + pinned IPs.
_url, validated_ips = await asyncio.to_thread(validate_and_resolve_url, url)
except httpx.InvalidURL as exc:
# Callers only guard ValueError; without translating this an IDNA-invalid host would 500 the
# caller (or escape dispatch) instead of failing closed as an unsafe webhook.
msg = f"webhook url has an invalid host: {exc}"
raise ValueError(msg) from exc
except SSRFProtectionError as exc:
msg = f"webhook url is not allowed: {exc}"
raise ValueError(msg) from exc
# Fall back to the floor IPs so dispatch can still DNS-pin with the global toggle off.
return validated_ips or floor_ips
async def folder_auth_type(flow: Flow, session: AsyncSession) -> str:
"""Read the flow's folder ``auth_type`` (``"none"`` | ``"apikey"`` | ``"oauth"``).
The single source of truth for what the card advertises (resolve_card_security)
and what the JSON-RPC route enforces, so the two can't drift. Plaintext read,
no decrypt. No folder / missing folder -> ``"none"`` (public).
"""
if flow.folder_id is None:
return "none"
# Query the folder explicitly; lazy-loading flow.folder would raise in async.
folder = (await session.exec(select(Folder).where(Folder.id == flow.folder_id))).first()View on GitHub (pinned to 976ec789d2)
Solutions
- Fix the hostname to a valid DNS name: replace underscores with hyphens, remove stray unicode characters
- Validate with httpx.URL(url) client-side — if it raises InvalidURL the server will reject it too
- Register the webhook under a clean canonical name (CNAME to the odd internal host if needed)
Example fix
# before url = "https://my_hook.example.com/cb" # after url = "https://my-hook.example.com/cb"
Defensive patterns
Strategy: validation
Validate before calling
import httpx
def webhook_host_idna_safe(url: str) -> bool:
try:
httpx.URL(url)
return True
except httpx.InvalidURL:
return False Try / catch
try:
await client.tasks.set_push_notification(task_id, cfg)
except InvalidParamsError as e:
if "invalid host" in str(e):
cfg.url = sanitize_hostname(cfg.url) # underscores->hyphens, strip unicode
await client.tasks.set_push_notification(task_id, cfg)
else:
raise Prevention
- Mirror the server: validate with httpx.URL before submitting any webhook
- Ban underscores/unicode in webhook hostnames in your config linting
- Use CNAMEs with clean names for oddly-named internal hosts
When it happens
Trigger: A webhook URL whose hostname contains characters that cannot be IDNA-encoded — e.g. embedded underscores ('my_hook.example.com' is actually accepted by some resolvers but rejected here), labels >63 chars, prohibited code points, or stray unicode punctuation in the host.
Common situations: Hostnames with underscores common in internal naming (service_name.internal); copy-pasting a URL with a smart quote/zero-width character; very long auto-generated subdomains exceeding per-label limits.
Related errors
- webhook url must be http or https
- webhook url has no host
- str(exc)
- webhook url resolves to a blocked address: {', '.join(blocke
- webhook url is not allowed: {exc}
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/01e9a4cb274c6b1e.
Report an issue: GitHub.