{"record":{"id":"debca0ff61e61d7f","repo":"HKUDS/DeepTutor","slug":"self-name-skill-detail-returned-invalid-json","errorCode":null,"errorMessage":"{self.name}: skill detail returned invalid JSON","messagePattern":"(.+?): skill detail returned invalid JSON","errorType":"http","errorClass":"HubError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/skill/hub.py","lineNumber":430,"sourceCode":"                if isinstance(payload.get(key), list):\n                    rows = payload[key]\n                    break\n        if rows is None:\n            raise HubError(f\"{self.name}: unrecognised catalog response shape\")\n        out: list[dict[str, Any]] = []\n        for row in rows:\n            if isinstance(row, dict):\n                listing = self._listing_from_row(row)\n                if listing is not None:\n                    out.append(listing)\n        return out\n\n    def detail(self, slug: str) -> dict[str, Any]:\n        \"\"\"Full metadata + SKILL.md body for one hub skill (browser detail view).\"\"\"\n        try:\n            payload = self._get(f\"/skills/{slug}\").json()\n        except ValueError as exc:\n            raise HubError(f\"{self.name}: skill detail returned invalid JSON\") from exc\n        if not isinstance(payload, dict):\n            raise HubError(f\"{self.name}: unrecognised skill detail shape\")\n        skill = payload.get(\"skill\") if isinstance(payload.get(\"skill\"), dict) else payload\n        listing = self._listing_from_row(skill) or {\"slug\": slug, \"name\": slug}\n        # Owner sometimes lives at the envelope top level, not inside ``skill``.\n        if not listing.get(\"owner\") and isinstance(payload.get(\"owner\"), dict):\n            owner = payload[\"owner\"]\n            listing[\"owner\"] = str(owner.get(\"displayName\") or owner.get(\"handle\") or \"\")\n            listing[\"owner_url\"] = str(owner.get(\"htmlUrl\") or \"\")\n        dist = payload.get(\"distTags\") if isinstance(payload.get(\"distTags\"), dict) else {}\n        listing[\"version\"] = str(dist.get(\"latest\") or listing.get(\"version\") or \"\")\n        listing[\"content\"] = str(skill.get(\"description\") or \"\")\n        # EduHub's ``tags`` field is a dist-tags map; the topical labels live in\n        # ``keywords``. Fall back to a list-shaped ``tags`` for other hubs.\n        keywords = skill.get(\"keywords\")\n        if not isinstance(keywords, list):\n            keywords = skill.get(\"tags\") if isinstance(skill.get(\"tags\"), list) else []\n        listing[\"tags\"] = [str(t) for t in keywords if str(t).strip()]","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/skill/hub.py#L412-L448","documentation":"Raised by HubProvider.detail when GET /skills/{slug} returns a body that fails JSON parsing. The body is HTML/plain-text/empty, so metadata and the SKILL.md body cannot be extracted.","triggerScenarios":"Calling detail('slug') when the hub's skill-detail endpoint returns an HTML 404/500 page, an empty body, or a text error — e.g. a slug route not implemented by the deployed hub version.","commonSituations":"Slug-specific routes missing on older hub versions; proxy error pages; base_url pointing at the web UI rather than the API; slug containing characters that trigger a gateway rejection.","solutions":["curl -i $BASE_URL/skills/<slug> and inspect status/content-type","Verify the slug exists via catalog/search first","Correct base_url to the API host","HTML-encode or validate the slug before calling detail"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"resp = httpx.get(f\"{BASE}/skills/{slug}\")\nct = resp.headers.get(\"content-type\", \"\")\nif resp.status_code != 200 or \"json\" not in ct:\n    skip_detail(slug)  # don't call detail()","typeGuard":null,"tryCatchPattern":"try:\n    d = hub.detail(slug)\nexcept HubError as e:\n    if \"invalid JSON\" in str(e):\n        log.warning(\"detail unavailable for %s\", slug); d = None\n    else: raise","preventionTips":["Validate slug format before calling","Cache successful detail responses"],"tags":["hub","detail","invalid-json"],"backgroundTag":"invalid-json-response","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}