nexu-io/open-design · error · ValueError
Missing Xiaohongshu API base URL
Error message
Missing Xiaohongshu API base URL
What it means
Raised in xiaohongshu_api.search_feeds when the base_url argument is empty after rstrip('/'). Note env.get_xiaohongshu_api_base always returns a default of http://host.docker.internal:18060 when XIAOHONGSHU_API_BASE is unset, so in the normal pipeline path this ValueError only fires if an explicit empty string is passed (or the env default is deliberately overridden to empty).
Source
Thrown at design-templates/last30days/scripts/lib/xiaohongshu_api.py:77
def _build_note_url(feed_id: str, xsec_token: str) -> str:
"""Build a stable Xiaohongshu note URL."""
if xsec_token:
return f"https://www.xiaohongshu.com/explore/{feed_id}?xsec_token={xsec_token}"
return f"https://www.xiaohongshu.com/explore/{feed_id}"
def search_feeds(
topic: str,
from_date: str,
to_date: str,
base_url: str,
depth: str = "default",
) -> List[Dict[str, Any]]:
"""Search Xiaohongshu feeds and normalize to web-item shape."""
base = (base_url or "").rstrip("/")
if not base:
raise ValueError("Missing Xiaohongshu API base URL")
# Quick login sanity check.
login = http.get(f"{base}/api/v1/login/status", timeout=8, retries=1)
is_logged_in = (
login.get("data", {}).get("is_logged_in")
if isinstance(login, dict) else False
)
if not is_logged_in:
raise http.HTTPError("Xiaohongshu API reachable but not logged in")
# API supports filters; use recency-oriented defaults.
publish_time = "一天内" if depth == "quick" else "一周内" if depth == "default" else "半年内"
payload = {
"keyword": topic,
"filters": {
"sort_by": "综合",
"note_type": "不限",
"publish_time": publish_time,View on GitHub (pinned to 5be4028344)
Solutions
- Let env.get_xiaohongshu_api_base supply its default; do not pass an explicit empty base_url.
- If overriding XIAOHONGSHU_API_BASE, set it to a real URL (e.g. http://localhost:18060).
- Validate base_url is non-empty before calling search_feeds.
Example fix
# before xiaohongshu_api.search_feeds(topic, frm, to, base_url='') # after from lib import env xiaohongshu_api.search_feeds(topic, frm, to, env.get_xiaohongshu_api_base(config))
Defensive patterns
Strategy: validation
Validate before calling
def search_feeds_safe(topic, frm, to, base_url, depth="default"):
base = (base_url or "").rstrip("/")
if not base:
raise ValueError("Xiaohongshu API base URL is required")
return xiaohongshu_api.search_feeds(topic, frm, to, base, depth=depth) Type guard
def has_base_url(base_url) -> bool:
return bool(base_url and base_url.strip()) Try / catch
null
Prevention
- Always obtain base_url via env.get_xiaohongshu_api_base(config) so the default applies.
- Never override XIAOHONGSHU_API_BASE to an empty string; unset it instead to get the default.
- Distinguish this config error from the runtime 'reachable but not logged in' HTTPError.
When it happens
Trigger: Calling search_feeds(..., base_url='') or base_url=None directly. Overriding XIAOHONGSHU_API_BASE to an empty string in config. A custom orchestrator that passes env.get_xiaohongshu_api_base result after stripping it to empty.
Common situations: Programmatic caller that built base_url from an unset env var without the env default. Test that monkeypatched the base to ''. Docker host unreachable is a DIFFERENT error (HTTPError 'reachable but not logged in'), not this one.
Related errors
- Cloudflare API token is required.
- existing config at ${where} is not valid JSON: ${err instanc
- existing config at ${where} is not a JSON object
- {role} must use a Gemini 3.1 preview model. Got: {model}
- Unknown config key: {args.key}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/a35a693f706e10f5.
Report an issue: GitHub.