infiniflow/ragflow · error · ValueError
KEENABLE_API_URL must be an https:// URL with a host, got {b
Error message
KEENABLE_API_URL must be an https:// URL with a host, got {base!r} What it means
ValueError raised by _base_url() in the Keenable tool when the KEENABLE_API_URL environment variable is not a usable HTTPS URL. The helper strips trailing '/', parses the URL, and only accepts https:// any host, or http:// strictly for localhost/127.0.0.1/::1 (local dev). Anything else — http:// to a remote host, missing scheme, no hostname — raises.
Source
Thrown at agent/tools/keenable.py:38
from urllib.parse import urlsplit
import requests
from agent.tools.base import ToolBase, ToolMeta, ToolParamBase
from common.connection_utils import timeout
def _base_url() -> str:
"""Resolve the Keenable API base URL from ``KEENABLE_API_URL`` (HTTPS enforced)."""
base = (os.environ.get("KEENABLE_API_URL") or "https://api.keenable.ai").rstrip("/")
parsed = urlsplit(base)
if parsed.hostname:
if parsed.scheme == "https":
return base
# Permit plain http only against a loopback host (local dev).
if parsed.scheme == "http" and parsed.hostname in {"localhost", "127.0.0.1", "::1"}:
return base
raise ValueError(f"KEENABLE_API_URL must be an https:// URL with a host, got {base!r}")
def _request(method: str, public_path: str, keyed_path: str, api_key: str, *, params=None, json=None, timeout_s: int = 30):
"""Call the keyed endpoint with X-API-Key when a key is set, else the keyless public one."""
api_key = (api_key or "").strip()
headers = {
"User-Agent": "keenable-ragflow",
# Attribution header the Keenable backend segments traffic by.
"X-Keenable-Title": "RAGFlow",
}
if api_key:
path = keyed_path
headers["X-API-Key"] = api_key
else:
path = public_path
resp = requests.request(method, f"{_base_url()}{path}", headers=headers, params=params, json=json, timeout=timeout_s)
resp.raise_for_status()
return resp.json()View on GitHub (pinned to 554fb1133a)
Solutions
- Set KEENABLE_API_URL to a full https URL with a host, e.g. https://api.keenable.ai.
- If you truly need plain http for local testing, the host must be exactly localhost, 127.0.0.1, or ::1.
- If the URL sits behind an http-only proxy, put a TLS terminator (nginx/caddy) in front and point the variable at the https endpoint.
- Unset the variable entirely to fall back to the default https://api.keenable.ai.
Example fix
# before export KEENABLE_API_URL=http://api.keenable.ai # ValueError # after export KEENABLE_API_URL=https://api.keenable.ai # local dev only: export KEENABLE_API_URL=http://127.0.0.1:8080
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlsplit
def valid_keenable_url(v: str) -> bool:
p = urlsplit((v or "").rstrip("/"))
return (p.scheme == "https" and bool(p.hostname)) or \
(p.scheme == "http" and p.hostname in {"localhost", "127.0.0.1", "::1"}) Try / catch
try:
keenable_search._invoke(query=q)
except ValueError as e:
if "KEENABLE_API_URL" in str(e):
fix_environment(); restart_service()
raise Prevention
- Set KEENABLE_API_URL once in deployment config with a full https:// URL and a smoke-test at deploy time.
- Add a config lint step (CI or bootstrap) that validates the env var with urlsplit before the agent runs.
- Leave the variable unset to use the default https://api.keenable.ai.
When it happens
Trigger: Setting KEENABLE_API_URL=http://api.keenable.ai (plain http off-loopback), KEENABLE_API_URL=api.keenable.ai (no scheme, parsed.hostname is None), an empty string after rstrip, or a URL like 'https://<spaces>' that fails host parsing.
Common situations: Operators copying an internal http:// endpoint URL from staging into production env config; docker-compose env files missing the scheme; typos like 'https:/api.keenable.ai' (single slash yields no netloc); proxies terminating TLS prompting someone to 'downgrade' to http.
Related errors
- Keenable 'realtime' mode requires an API key
- 500
- Encryption key not provided and RAGFLOW_CRYPTO_KEY environme
- main() returned a non-JSON-serializable value.
- WhatsApp session is not running.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/6f1d0ede90b71cf6.
Report an issue: GitHub.