HKUDS/DeepTutor · error · HubError
: catalog returned invalid JSON
Error message
{self.name}: catalog returned invalid JSON What it means
Raised by HubProvider.catalog when the HTTP response body cannot be parsed as JSON (response.json() raises ValueError). The catalog endpoint returned HTML, plain text, or an empty body — typically a gateway error page or wrong base_url.
Solutions
- Check response status and Content-Type: curl -i $BASE_URL/skills
- Fix base_url in settings/skill_hubs.json to the actual API root
- If a proxy intercepts the call, add an exception or correct headers
- Retry transient gateway failures (502/503) before giving up
Defensive patterns
Strategy: try-catch
Validate before calling
resp = httpx.get(f"{BASE}/skills")
if "application/json" not in resp.headers.get("content-type", ""):
raise RuntimeError(f"non-JSON content-type: {resp.status_code}") Try / catch
try:
listings = hub.catalog()
except HubError as e:
if "invalid JSON" in str(e):
log.warning("hub returned non-JSON; possibly down: %s", e)
return []
raise Prevention
- Monitor hub Content-Type in integration tests
- Retry on 5xx before surfacing to users
When it happens
Trigger: Calling catalog() (used by hub_catalog and the tests test_clawhub_catalog_normalises_rows / test_clawhub_catalog_uses_search_when_queried) when /skills or /search responds with non-JSON such as a 502 HTML page, an empty body, or a text/plain message.
Common situations: Reverse proxy or CDN serving an error page; base_url misconfigured to a non-API host; hub behind auth wall returning an HTML login redirect; trailing-slash or path-join bug producing a 404 HTML page.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- : invalid JSON listing skills
- : publish request failed
- : skill detail returned invalid JSON
- : unrecognised catalog response shape
- Channel onboarding provider request failed
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/7c082cdb1834a150.
Report an issue: GitHub.
Appendix: source
Thrown at deeptutor/services/skill/hub.py:408
def catalog(
self, *, query: str = "", limit: int = 50, sort: str = "createdAt"
) -> list[dict[str, Any]]:
"""List skills published on the hub, for the in-app skill browser.
Uses ``/search`` when a query is given (server-side relevance) and the
plain ``/skills`` explore feed otherwise. Rows carry display name,
summary, version, download/star counts and owner — everything the
DeepTutor-native browser renders without a second round-trip.
"""
if query.strip():
response = self._get("/search", q=query.strip(), limit=limit)
else:
response = self._get("/skills", limit=limit, sort=sort)
try:
payload = response.json()
except ValueError as exc:
raise HubError(f"{self.name}: catalog returned invalid JSON") from exc
rows = payload if isinstance(payload, list) else None
if rows is None and isinstance(payload, dict):
for key in ("results", "skills", "items"):
if isinstance(payload.get(key), list):
rows = payload[key]
break
if rows is None:
raise HubError(f"{self.name}: unrecognised catalog response shape")
out: list[dict[str, Any]] = []
for row in rows:
if isinstance(row, dict):
listing = self._listing_from_row(row)
if listing is not None:
out.append(listing)
return out
def detail(self, slug: str) -> dict[str, Any]:
"""Full metadata + SKILL.md body for one hub skill (browser detail view)."""View on GitHub (pinned to 3e82f13042)