{"record":{"id":"29b6a0353d218c0e","repo":"HKUDS/DeepTutor","slug":"self-name-this-hub-does-not-support-search","errorCode":null,"errorMessage":"{self.name}: this hub does not support search.","messagePattern":"(.+?): this hub does not support search\\.","errorType":"validation","errorClass":"HubError","httpStatus":null,"severity":"warning","filePath":"deeptutor/services/skill/hub.py","lineNumber":562,"sourceCode":"            return {}\n\n\nclass CommandProvider:\n    \"\"\"Generic fetch-by-command provider for registries without a public API.\n\n    The configured ``fetch_cmd`` template receives ``{slug}``, ``{version}``\n    (empty string when unpinned) and ``{dest}`` — it must leave the package\n    (a ``SKILL.md`` tree, or a zip we can extract) under ``{dest}``. The\n    command runs without a shell; pipes and substitutions won't work, which\n    is the point.\n    \"\"\"\n\n    def __init__(self, name: str, *, fetch_cmd: str) -> None:\n        self.name = name\n        self._fetch_cmd = fetch_cmd\n\n    def search(self, query: str, *, limit: int = 10) -> list[HubSkillRef]:\n        raise HubError(f\"{self.name}: this hub does not support search.\")\n\n    def verify(self, slug: str, *, version: str | None = None) -> HubVerdict:\n        return HubVerdict(status=\"unknown\", detail=\"command hubs have no verdict API\")\n\n    def fetch(self, slug: str, *, version: str | None = None) -> FetchedSkill:\n        tmp = Path(tempfile.mkdtemp(prefix=\"deeptutor-skill-\"))\n        dest = tmp / \"fetched\"\n        dest.mkdir()\n        argv = [\n            part.format(slug=slug, version=version or \"\", dest=str(dest))\n            for part in shlex.split(self._fetch_cmd)\n        ]\n        try:\n            completed = subprocess.run(\n                argv,\n                cwd=str(tmp),\n                capture_output=True,\n                text=True,","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/skill/hub.py#L544-L580","documentation":"Raised by CommandProvider.search — command-based hubs (type \"command\" in settings) have no HTTP search API, only a fetch command. Any search() call on such a provider is unsupported by design.","triggerScenarios":"Configuring a hub entry with \"type\": \"command\" and then calling skill_search / hub.search against that hub name, or running `skill search --hub <command-hub>`.","commonSituations":"Switching a hub config from clawhub to command and forgetting search no longer works; scripts assuming every provider implements search.","solutions":["Search a different hub that supports search (e.g. the default clawhub)","Guard with hasattr/provider capability checks before calling search","Switch the hub type back to clawhub if the hub actually has an HTTP API","For command hubs, browse slugs out-of-band (e.g. the command's own docs)"],"exampleFix":"# before\nhub = get_hub_provider('mycmdhub')\nhub.search('query')  # raises\n# after\nhub = get_hub_provider('clawhub')\nhub.search('query')","handlingStrategy":"type-guard","validationCode":"provider = get_hub_provider(hub)\nif not hasattr(provider, 'search') or type(provider).__name__ == 'CommandProvider':\n    raise SystemExit(f'{hub} cannot search; use a clawhub-type hub')","typeGuard":"def supports_search(p) -> bool:\n    from deeptutor.services.skill.hub import CommandProvider\n    return not isinstance(p, CommandProvider)","tryCatchPattern":"try:\n    hub.search(q)\nexcept HubError as e:\n    if \"does not support search\" in str(e): use_default_hub()\n    else: raise","preventionTips":["Check provider type before calling search","Route searches to clawhub-type hubs only"],"tags":["command-hub","search","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}